[
  {
    "path": ".editorconfig",
    "content": "# EditorConfig is awesome: http://EditorConfig.org\n\n# top-most EditorConfig file\nroot = true\n\n# Unix-style newlines with a newline ending every file\n[*]\nend_of_line = lf\ninsert_final_newline = true\ncharset = utf-8\nindent_style = space\nindent_size = 4\nmax_line_length=120\n\n[*.gradle]\nindent_size = 2\n"
  },
  {
    "path": ".gitattributes",
    "content": "*.cpp linguist-language=java\n*.cc linguist-language=java\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "## 提issue小提示\n为了尽快定位问题，需要提供足够的信息，请按照我们的要求格式来提问。***如果您不按照格式提问，我们将无法回复您的问题***\n\n#### 操作说明\n详细说明操作那个界面，每一步骤都要说得详细，如果是SDK或者api使用问题，需要详细说明调用的那个函数，参数都是什么。\n\n#### 表现现象\n描述一下什么现象，比如说函数返回error，errorcode是多少，或者界面上是什么状态，比如发送消息显示发送失败的红点。不要笼统的说功能有问题，不起作用。\n\n#### 预期结果\n你认为正确的表现应该是什么样的。\n\n#### 补充条件\n是否是必现的，还是偶现的？是否只有在特殊的网络/设备/平台上出现，还是所有的都出现。还有您用的版本是什么时候的，是不是最新版\n\n#### demo对比结果\n请用demo对比测试，demo上是什么状态。\n\n#### 检索已有问题\n除了可以检索已有issue外，还可以去野火论坛查找已有问题，论坛地址为 https://bbs.wildfirechat.cn\n\n#### star 我们\n给我们点个star，可以及时接收到我们回复信息，另外也是对我们支持人员辛苦工作的认可，激励我们更好更快地为大家服务。\n"
  },
  {
    "path": ".gitignore",
    "content": "/build\n*/build/\n/target/\n/parser/target/\n/benchmarking/target/\n.idea/\n*.iml\nbroker/target/\nclient/target/\nparser_commons/target/\nnetty_parser/target/\nnetty_parser/target/\nparser_commons/target/\ndistribution/target/\nbroker/moquette.log\nbroker/runner\n/bundle/target/\n/bundle/runner/\n/osgi_test/target/\n/perf/target/\n/mapdb_storage/target/\n*~\n*.log*\n.DS_Store\n.settings/\n.project\n.classpath\n/*/bin/\n*.swp\n\n*.class\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.war\n*.ear\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\nbroker/*moquette_store.*\nembedding_moquette/target/\nbroker/nb-configuration.xml\nbroker/nbactions-Server.xml\n\nmaven-metadata.xml\n/.gradle/\n/bin/\nbroker/config/git.properties\ndistribution/src/main/resources/git.properties\nlicense/target\nserver/target\nbroker/h2db\nbroker/media\ncommon/target\nserver/target\nsdk/target\nmoments/target\nmonitor\nwildfire_jmeter\ngit.properties\nwildfirechat.license\nbroker/logs\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: java\njdk:\n  - oraclejdk8\nbefore_cache:\n  - rm -f  $HOME/.gradle/caches/modules-2/modules-2.lock\n  - rm -fr $HOME/.gradle/caches/*/plugin-resolution/\ncache:\n  directories:\n    - $HOME/.gradle/caches/\n    - $HOME/.gradle/wrapper/\n\nscript:\n    - ./gradlew install test\n"
  },
  {
    "path": "LICENSE",
    "content": "Creative Commons Attribution-NoDerivs 3.0 Unported\n\nCREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN \"AS-IS\" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.\n\nLicense\n\nTHE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE (\"CCPL\" OR \"LICENSE\"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.\n\nBY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.\n\n1. Definitions\na. \"Adaptation\" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image (\"synching\") will be considered an Adaptation for the purpose of this License.\nb. \"Collection\" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License.\nc. \"Distribute\" means to make available to the public the original and copies of the Work through sale or other transfer of ownership.\nd. \"Licensor\" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License.\ne. \"Original Author\" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast.\nf. \"Work\" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work.\ng. \"You\" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation.\nh. \"Publicly Perform\" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images.\ni. \"Reproduce\" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium.\n2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws.\n3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below:\na. to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; and,\nb. to Distribute and Publicly Perform the Work including as incorporated in Collections.\nc. For the avoidance of doubt:\ni. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License;\nii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and,\niii. Voluntary License Schemes. The Licensor waives the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License.\nThe above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats, but otherwise you have no rights to make Adaptations. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved.\n\n4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions:\na. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(b), as requested.\nb. If You Distribute, or Publicly Perform the Work or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution (\"Attribution Parties\") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work. The credit required by this Section 4(b) may be implemented in any reasonable manner; provided, however, that in the case of a Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties.\nc. Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation.\n5. Representations, Warranties and Disclaimer\nUNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.\n\n6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\n7. Termination\na. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License.\nb. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above.\n8. Miscellaneous\na. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License.\nb. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.\nc. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent.\nd. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You.\ne. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law.\nCreative Commons Notice\n\nCreative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor.\n\nExcept for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark \"Creative Commons\" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License.\n\nCreative Commons may be contacted at http://creativecommons.org/.\n\n"
  },
  {
    "path": "LICENSE_996",
    "content": "Copyright (c) <2019> <wildfirechat>\n\nAnti 996 License Version 1.0 (Draft)\n\nPermission is hereby granted to any individual or legal entity\nobtaining a copy of this licensed work (including the source code,\ndocumentation and/or related items, hereinafter collectively referred\nto as the \"licensed work\"), free of charge, to deal with the licensed\nwork for any purpose, including without limitation, the rights to use,\nreproduce, modify, prepare derivative works of, distribute, publish \nand sublicense the licensed work, subject to the following conditions:\n\n1. The individual or the legal entity must conspicuously display,\nwithout modification, this License and the notice on each redistributed \nor derivative copy of the Licensed Work.\n\n2. The individual or the legal entity must strictly comply with all\napplicable laws, regulations, rules and standards of the jurisdiction\nrelating to labor and employment where the individual is physically\nlocated or where the individual was born or naturalized; or where the\nlegal entity is registered or is operating (whichever is stricter). In\ncase that the jurisdiction has no such laws, regulations, rules and\nstandards or its laws, regulations, rules and standards are\nunenforceable, the individual or the legal entity are required to\ncomply with Core International Labor Standards.\n\n3. The individual or the legal entity shall not induce or force its\nemployee(s), whether full-time or part-time, or its independent\ncontractor(s), in any methods, to agree in oral or written form, to\ndirectly or indirectly restrict, weaken or relinquish his or her\nrights or remedies under such laws, regulations, rules and standards\nrelating to labor and employment as mentioned above, no matter whether\nsuch written or oral agreement are enforceable under the laws of the\nsaid jurisdiction, nor shall such individual or the legal entity\nlimit, in any methods, the rights of its employee(s) or independent\ncontractor(s) from reporting or complaining to the copyright holder or\nrelevant authorities monitoring the compliance of the license about\nits violation(s) of the said license.\n\nTHE LICENSED WORK IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN ANY WAY CONNECTION WITH THE\nLICENSED WORK OR THE USE OR OTHER DEALINGS IN THE LICENSED WORK.\n"
  },
  {
    "path": "LICENSE_mqtt-jmeter",
    "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 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": "README.md",
    "content": "# 野火IM解决方案\n野火IM是专业级的即时通讯和实时音视频整体解决方案，由北京野火无限网络科技有限公司维护和支持。\n\n## 功能特性\n* 极致地硬件利用率，IM服务最低128M内存即可运行，上不封顶。\n* 协议先进，采用MQTT+Protobuf组合，流量和性能极致优化。\n* 性能强大，专业版IM服务支持百万在线和集群部署，业内顶尖性能水平，详情参考野火性能报告。\n* 部署运维简单，依赖服务少，稍加配置一键启动。\n* 安全加密。网络连接AES加密。客户端数据库SqlCipher加密。安全无小事。\n* 全平台客户端，支持Android、iOS、鸿蒙、Web、小程序、UniApp、Flutter、Windows、Mac OS、Linux等所有常见平台。\n* 四端同时在线（移动端，pc端，web端和小程序端），数据和状态多端完美同步。\n* 支持国产化。支持国产化操作系统、国产化芯片和国产数据库。支持国密加密。\n* 客户端使用微信[mars](https://github.com/tencent/mars)连接库，野火IM可能是最适应中国网络国情的即时通讯服务。\n* 支持加速点加速，即可用于全球应用，也可用于政企内外双网复杂的网络环境。\n* 支持阅读回执和在线状态功能，适用于办公环境。\n* 音视频多种解决方案，丰俭由人，可自由选择。\n* 高级音视频功能强大，支持9人以上的群组视频通话，支持1080P视频，支持会议模式，支持百人以上会议，支持服务器端录制。\n* 全私有部署，可不依赖任何第三方服务，完全内网部署。\n* 功能齐全，涵盖所有常见即时通讯功能。另外具有强大的可扩展能力。代码开源率高，二次开发简单。\n* 结构设计合理，客户端分功能库、UI库和应用三层。应用成熟完善，开箱即用，也可把SDK嵌入其它应用。\n* 拥有应用开放平台，可以开发和创建自建应用，扩展您的工作台。\n* API丰富，方便与其它服务系统的对接。\n* 拥有机器人和公众号功能，免费的频道（公众号）管理后台。\n* 超级群组功能，可以支持万人大群。\n* 支持多个IM服务组网互通，打破孤岛，适用于集团公司下多个分公司互联互通。\n* 社区版IM服务和移动端免费商用，可以免费构建出完备的移动互联网应用。\n* 收费项目非常便宜，野火独有的试用模式，可以先部署到客户环境试用6个月，试用满意后再购买，避免上当受骗。\n* 技术支持专业高效，***核心研发***及时处理issue和工单，能最快解决用户的技术难题。技术支持不收费，让客户顺利使用是我们最大的愿望。\n\n## 野火开源项目\n主要包括以下项目：\n\n| [GitHub仓库](https://github.com/wildfirechat)                                    | [码云仓库](https://gitee.com/wfchat)                                        | 说明                                                                                      \n|--------------------------------------------------------------------------------|-------------------------------------------------------------------------| --------------------------------------------------------------------------\n| [im-server](https://github.com/wildfirechat/im-server)                         | [im-server](https://gitee.com/wfchat/im-server)                         | 野火社区版IM服务，野火IM的核心服务，处理所有IM相关业务。  |\n| [app-server](https://github.com/wildfirechat/app-server)                       | [app-server](https://gitee.com/wfchat/app-server)                       | Demo应用服务，模拟客户的应用服登陆处理逻辑及部分二次开发示例。 |\n| [robot_server](https://github.com/wildfirechat/robot_server)                   | [robot_server](https://gitee.com/wfchat/robot_server)                   | 机器人服务，演示野火机器人对接其它系统的方法。 |\n| [push_server](https://github.com/wildfirechat/push_server)                     | [push_server](https://gitee.com/wfchat/push_server)                     | 推送服务器，可以对接所有的系统厂商推送服务或者第三方推送服务。 |\n| [wf-minio](https://github.com/wildfirechat/WF-minio)                           | [wf-minio](https://gitee.com/wfchat/WF-minio)                           | 私有对象存储服务，用来支持野火IM专业版的文件存储。 |\n| [wf-janus](https://github.com/wildfirechat/wf-janus  )                         | [wf-janus](https://gitee.com/wfchat/wf-janus  )                         | 高级音视频媒体服务。 |\n| [open-platform](https://github.com/wildfirechat/open-platform)                 | [open-platform](https://gitee.com/wfchat/open-platform)                 | 野火开放平台服务。  |\n| [daily-report](https://github.com/wildfirechat/daily-report)                   | [daily-report](https://github.com/wildfirechat/daily-report)            | 野火开放平台日报 demo服务。 |\n| [channel-platform](https://github.com/wildfirechat/channel-platform)           | [channel-platform](https://gitee.com/wfchat/channel-platform)           | 野火频道(公众号)平台服务。  |\n| [organization-platform](https://github.com/wildfirechat/organization-platform) | [organization-platform](https://gitee.com/wfchat/organization-platform) | 野火组织通讯录服务。  |\n| [archive-server](https://github.com/wildfirechat/archive-server)               | [archive-server](https://gitee.com/wfchat/archive-server)               | 野火组织通讯录服务。  |\n| [android-chat](https://github.com/wildfirechat/android-chat)                   | [android-chat](https://gitee.com/wfchat/android-chat)                   | 野火IM Android SDK源码和App源码。 |\n| [ios-chat](https://github.com/wildfirechat/ios-chat)                           | [ios-chat](https://gitee.com/wfchat/ios-chat)                           | 野火IM iOS SDK源码和App源码。|\n| [pc-chat(electron)](https://github.com/wildfirechat/vue-pc-chat)               | [pc-chat(electron)](https://gitee.com/wfchat/vue-pc-chat)               | 基于[Electron](https://electronjs.org/)开发的PC 端                   |                         |\n| [pc-chat(Qt)](https://github.com/wildfirechat/qt-pc-chat)                      | [pc-chat(Qt)](https://gitee.com/wfchat/qt-pc-chat)                      | 基于Qt开发的PC 端                   |                         |\n| [web-chat](https://github.com/wildfirechat/vue-chat)                           | [web-chat](https://gitee.com/wfchat/vue-chat)                           | 野火IM Web 端, [体验地址](https://web.wildfirechat.cn)。  |\n| [wx-chat](https://github.com/wildfirechat/wx-chat)                             | [wx-chat](https://gitee.com/wfchat/wx-chat)                             | 小程序平台的Demo(支持微信、百度、阿里、字节、QQ 等小程序平台)。  |\n| [uni-chat](https://github.com/wildfirechat/uni-chat)                           | [uni-chat](https://gitee.com/wfchat/uni-chat)                           | UniApp平台移动端应用(使用原生插件)。   |\n| [uni-wfc-client](https://github.com/wildfirechat/uni-wfc-client)               | [uni-wfc-client](https://gitee.com/wfchat/uni-wfc-client)               | UniApp平台原生插件。已[商店](https://ext.dcloud.net.cn/plugin?id=7895)上架   |\n| [flutter-chat](https://github.com/wildfirechat/flutter-chat)                   | [flutter-chat](https://gitee.com/wfchat/flutter-chat)                   | Flutter平台原生插件，支持IM和音视频通话。   |\n| [docs](https://github.com/wildfirechat/docs)                                   | [docs](https://gitee.com/wfchat/docs)                                   | 野火IM相关文档，包含设计、概念、开发、使用说明，[在线查看](https://docs.wildfirechat.cn/)。 |\n\n## 野火开发文档\n[在线文档](https://docs.wildfirechat.cn/)\n\n## 野火IM论坛\n[野火IM论坛](https://bbs.wildfirechat.cn)\n\n## 野火性能测试报告及测试方法\n[Github](https://github.com/wildfirechat/Performance_Test), [码云](https://gitee.com/wfchat/Performance_Test)。\n\n## 野火Demo\n请使用微信扫码下载安装体验野火IM移动客户端\n\n![野火IM](http://static.wildfirechat.cn/download_qrcode.png)\n\nWeb客户端点击[这里](https://web.wildfirechat.cn)\n\nPC客户端点[这里](https://github.com/wildfirechat/vue-pc-chat/releases)下载安装。\n\n小程序客户端请用微信扫码\n\n![野火IM](http://static.wildfirechat.net/wx.jpg)\n\n## 快速开始\n可以按照[快速开始](https://docs.wildfirechat.cn/quick_start/)来部署应用服务和IM服务，然后打包移动端，就可以完成聊天和通话功能。\n\n之后再部署开放平台服务、频道（公众号）服务、机器人服务、推送服务、Turn服务（音视频服务）来实现完整的应用功能，详情可以详细阅读文档。\n\n## 联系我们\n商务合作请微信联系：\n\n* 微信1：wildfirechat\n* 微信2：wfchat\n\n## 问题交流\n\n1. 如果大家发现bug，请在GitHub或码云提issue；如果有需求也请给我们提issue。\n2. 其他问题，请到[野火IM论坛](http://bbs.wildfirechat.cn/)进行交流学习\n3. 关注我们的公众号。我们有新版本发布或者有重大更新会通过公众号通知大家，另外我们也会不定期的发布一些关于野火IM的技术介绍。\n\n<img src=\"http://static.wildfirechat.cn/wx_wfc_qrcode.jpg\" width = 50% height = 50% />\n\n我们有核心研发工程师轮流值班处理issue和论坛，会及时处理的，疑难Bug的修改和新需求的开发我们也会尽快解决。\n\n\n## 编译\n```\nmvn clean package\n```\n生成的目标文件在```./distribution/target/distribution-xxxx-bundle-tar.tar.gz```\n\n## 配置\n解压```distribution-xxxx-bundle-tar.tar.gz```，修改解压出来的```config```目录下的```wildfirechat.conf```，可以阅读配置文件注释和文档，对其它配置项进行调整。\n\n## 运行\n在解压```distribution-xxxx-bundle-tar.tar.gz```后的目录下运行如下命令：\n```\n./bin/wildfirechat.sh\n```\n\n## 验证\n1. 在浏览器中输入地址 ```http://${ip}/api/version```可以看到返回一个json文件。\n2. 部署[应用服务](https://github.com/wildfirechat/app-server)，配置和编译[Android客户端](https://github.com/wildfirechat/android-chat)和[iOS客户端](https://github.com/wildfirechat/ios-chat)进行验证。详情可参考[快速开始](https://docs.wildfirechat.cn/quick_start/)。\n\n## 打包RPM格式\n打包会生成Java包和deb安装包，如果需要rpm安装包，请在```distribution/pom.xml```中取消注释生成rpm包的plugin。另外还需要本地安装有rpm，在linux或者mac系统中很容易安装，在windows系统需要安装cygwin并安装rpm，具体信息请百度查询。\n\n修改之后运行编译命令```mvn clean package```，rpm包生成在```distribution/target```目录下。\n\n## Epoll\n在linux系统中打开Epoll开关可以提高性能，默认软件包内打包的是x86_64的epoll native sdk。如果是arm64的机器，可以把[broker pom](./broker/pom.xml)文件中修改如下：\n```xml\n<dependency>\n    <groupId>io.netty</groupId>\n    <artifactId>netty-transport-native-epoll</artifactId>\n    <version>${netty.version}</version>\n<!--    <classifier>linux-x86_64</classifier>-->\n    <classifier>linux-aarch_64</classifier>\n</dependency>\n```\n然后重新打包。专业版IM服务软件包中有arm64架构的sdk，可以直接替换。epoll只支持x86_64和arm64两个架构，其他架构不要把epoll开关打开。\n\n## 升级说明\n1. 从0.42 版本增加了群成员数限制，默认为2000。如果您从之前的版本升级到这个版本或以后，需要注意到群成员数的限制。升级之后超出限制的群不受影响，但不能继续加人，如果您想修改默认值，可以在升级版本之后，修改t_setting表，把默认的大小改为您期望的人数。另外修改t_group表，把已经存在的群组max_member_count改成您期望的，然后重启。\n2. 0.50版本添加了是否允许客户端发送群操作通知的配置。如果您在客户端自定义群通知，需要在服务器端配置允许，没有使用自定义群操作通知的不受影响。***\n3. 0.46和0.47版本升级到0.48及以后版本时，可能会提示flyway migrate 38错误，请执行 [修复脚本](https://github.com/wildfirechat/server/blob/wildfirechat/flyway_repaire_migrate_38.sql) 进行修复。0.46和0.47版本之外的版本不会出现此问题。\n4. 从0.54之前版本升级到0.54及以后版本时，会提示flyway migrate错误。因为0.54版本删除了sql脚本中默认敏感词的内容，flyway checksum失败。请执行```update flyway_schema_history set checksum = 0 where script = 'V17__add_default_sensitive_word.sql';```来修复。\n5. 从0.59之前的版本升级到之后的版本执行数据库升级时间比较长，请耐心等待提示运行成功，避免中途中断。\n6. 0.62/0.63 版本有严重的问题，请使用0.64及以后版本，或者0.61版。\n7. 从0.68 版本起添加了pc在线是否默认手机接收推送的开关，默认为开，与以前版本作用相反，请注意兼容（可以关掉与之前保持一致或者升级客户端）\n8. 从0.78 版本起把MySQL数据库中关键字都改为大小写敏感，另外生成id的方法也做了改变，只生成小写的id，避免出现id重复的问题，建议所有客户都升级\n9. 从0.79 版本起把log4j升级到log4j2，因为log4j已经不再维护而且还有已知的漏洞，建议所有客户都升级，升级时注意更新log4j2的配置文件\n10. 0.97版本更改了启动脚本```wildfirechat.sh```，如果是升级服务，请注意更新启动脚本。\n\n## 维护说明\n野火设计理念当中，IM服务和客户端协议栈构成个管道工具，数据在人和人或者人和服务或者服务和服务之间传递，可以通过Server API和自定义消息来对接和开发业务。业务系统把IM系统当作一个工具来使用，是不需要把任何业务逻辑写在IM服务中的。\n\n如果修改了IM服务可能会引起跟客户端协议栈的不兼容，以后也没有可能从社区版IM服务迁移到专业版IM服务，还有一旦修改就跟我们代码不一样了，如果出了问题我们就无法分析和解决。所以 ***我们强烈不推荐在IM服务修改代码，如果修改过就不再提供任何技术支持和服务了***。除了IM服务以外的所有代码可以任意修改。\n\n现有接口足够对接和二开任何业务了，如果发现无法实现你们的业务需求，可以在[论坛](https://bbs.wildfirechat.cn)来咨询，我们会分析如何实现，如果需要添加新接口，我们会及时免费添加。请切记：***不要修改IM服务的代码!*** ***不要修改IM服务的代码!*** ***不要修改IM服务的代码!***\n\n详细维护说明请参考 [野火维护说明](https://docs.wildfirechat.cn/base_knowledge/maintain.html)。\n\n## 服务对象\n因为野火的使用范围比较广，难免被一些不法分子利用，国内反诈反赌力度很大，所以国内多地警方都跟我们都有过联系。***为了预防我们的产品被用于非法目的，试用及购买只能支持境内法人单位，不接受个人或者境外团体。如果我们发现产品被用于非法目的，我们会立即停止技术支持服务并且报警和配合警方调查。请用于非法目的用户绕行！***\n\n## 群的性能问题\n群的大小和性能不是线性相关的，而是O(N²)的关系，这是群的特性决定的。所以社区版IM服务很难支持很大的群人数，我们建议最大群不要超过500人，像微信的群大小一样。修改方法是修改数据库中```t_settings```表中的群最大人数。\n\n如果是专业版IM服务，普通群性能会有些加强，但也不会提高太多，所以我们就开发了超级群，可以支持上万群成员。关于超级群，请参考[野火超级群组](https://mp.weixin.qq.com/s/ov5ZiaEIUZuvgFBXOrcjbg)。现有客户有接近10W的群组成员能够流畅稳定地运行。\n\n## 网络问题\n如果是自建机房或者私有网络，可能会有跨运营商瓶颈，详情请参考[《从野火 IM 的网络踩坑经历，聊聊跨运营商访问的那些坑》](https://mp.weixin.qq.com/s/Pa8b93oMk58fjMgwtwmePQ)。\n\n## 常见问题\n请参考文档[常见问题](https://docs.wildfirechat.cn/faq/server.html)\n\n## 应用截图\n登录界面\n\n<img src=\"./screenshots/1_login.png\" width = 50% height = 50% />\n\n会话列表\n\n<img src=\"./screenshots/2_conversation_list.png\" width = 50% height = 50% />\n\n好友列表\n\n<img src=\"./screenshots/3_contacts_list.png\" width = 50% height = 50% />\n\n工作台\n\n<img src=\"./screenshots/4_workplatform.png\" width = 50% height = 50% />\n\n发现\n\n<img src=\"./screenshots/5_discover.png\" width = 50% height = 50% />\n\n我的页面\n\n<img src=\"./screenshots/6_settings.png\" width = 50% height = 50% />\n\n消息聊天\n\n<img src=\"./screenshots/7_conversation.png\" width = 50% height = 50% />\n\n动态表情\n\n<img src=\"./screenshots/8_conversation_sticker.png\" width = 50% height = 50% />\n\n语音消息\n\n<img src=\"./screenshots/9_conversation_voice_msg.png\" width = 50% height = 50% />\n\n位置消息\n\n<img src=\"./screenshots/10_conversation_location.png\" width = 50% height = 50% />\n\n拍摄图片或者小视频\n\n<img src=\"./screenshots/11_conversation_capture.jpeg\" width = 50% height = 50% />\n\n会话设置\n\n<img src=\"./screenshots/13_conversation_settings.png\" width = 50% height = 50% />\n\n朋友圈\n\n<img src=\"./screenshots/14_moments.png\" width = 50% height = 50% />\n\n新好友\n\n<img src=\"./screenshots/15_new_friends.png\" width = 50% height = 50% />\n\n多人视频通话\n\n<img src=\"./screenshots/16_videocall.png\" width = 50% height = 50% />\n\n会议主页\n\n<img src=\"./screenshots/17_conference_home.png\" width = 50% height = 50% />\n\n会议详情\n\n<img src=\"./screenshots/18_conference_info.png\" width = 50% height = 50% />\n\n会议界面\n\n<img src=\"./screenshots/19_conference.png\" width = 50% height = 50% />\n\nPC客户端界面\n\n<img src=\"./screenshots/20_pc.png\"/>\n\n移动客户端、PC客户端和Web客户端三端同框\n\n<img src=\"./screenshots/21_three_platform.png\" />\n\n小程序客户端\n\n<img src=\"./screenshots/22_micro_app.jpeg\" width = 50% height = 50% />\n\n公众号管理后台\n\n<img src=\"./screenshots/23_channel.png\"/>\n\n开放平台管理后台\n\n<img src=\"./screenshots/24_open_platform.png\" />\n\nIM服务管理后台\n\n<img src=\"./screenshots/25_im_admin.png\" />\n\n> 更多详细信息请下载demo进行体验。\n\n## 特别感谢\n1. [moquette](https://github.com/moquette-io/moquette) 本项目是基于此项目二次开发而来，处理MQTT相关业务。\n2. [loServer](https://github.com/looly/loServer) 本项目使用loServer处理HTTP相关业务。\n\n*** 对他们表示诚挚的感谢🙏 ***\n\n## License\n\n1. Under the Creative Commons Attribution-NoDerivs 3.0 Unported license. See the [LICENSE](https://github.com/wildfirechat/server/blob/wildfirechat/LICENSE) file for details.\n"
  },
  {
    "path": "broker/config/hazelcast.xml",
    "content": "\n<!--    # 本配置文件为debug使用，修改这里不会在Release包中生效。Release中包含的配置文件在 ${Porject_Path}/distribution/src/main/resources目录下-->\n\n\n<hazelcast\n    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n    xsi:schemaLocation=\"http://www.hazelcast.com/schema/config\n  http://www.hazelcast.com/schema/config/hazelcast-config-3.5.xsd\"\n    xmlns=\"http://www.hazelcast.com/schema/config\">\n    <network>\n        <join>\n            <multicast enabled=\"false\"/>\n        </join>\n    </network>\n\n    <properties>\n        <property name=\"hazelcast.logging.type\">slf4j</property>\n    </properties>\n\n    <!-- map eviction -->\n    <!-- http://docs.hazelcast.org/docs/latest-development/manual/html/Distributed_Data_Structures/Map/Map_Eviction.html -->\n    <map name=\"messages_map\">\n        <!-- 7 days -->\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.MessageLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <map name=\"groups_map\">\n        <!-- 7 days -->\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.GroupLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <map name=\"users\">\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.UserLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <map name=\"user_status\">\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.UserStatusLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <map name=\"user_friends_empty\">\n        <time-to-live-seconds>86400</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n    </map>\n\n\n\n    <set name=\"node_ids\"/>\n\n    <multimap name=\"user_setting\">\n    </multimap>\n\n    <multimap name=\"group_members\">\n    </multimap>\n\n    <map name=\"chatrooms\">\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.ChatroomLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <map name=\"user_chatroom\">\n    </map>\n\n    <multimap name=\"chatroom_black\">\n    </multimap>\n\n    <multimap name=\"chatroom_manager\">\n    </multimap>\n\n    <map name=\"robots\">\n        <!-- 7 days -->\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.RobotLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n    \n    <map name=\"devices\">\n        <!-- 7 days -->\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.DeviceLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <multimap name=\"user_robots\">\n    </multimap>\n\n    <multimap name=\"user_devices\">\n    </multimap>\n\n    <multimap name=\"chatroom_members\">\n    </multimap>\n\n    <multimap name=\"user_friends\">\n    </multimap>\n\n    <multimap name=\"user_friends_request\">\n    </multimap>\n\n    <map name=\"channels_map\">\n        <!-- 7 days -->\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.ChannelLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <multimap name=\"channel_listeners\">\n    </multimap>\n</hazelcast>\n"
  },
  {
    "path": "broker/config/wildfirechat.conf",
    "content": "#\n#\n# 本配置文件为debug使用，修改这里不会在Release包中生效。Release中包含的配置文件在 ${Porject_Path}/distribution/src/main/resources目录下\n#\n#\n\n\n\n#*********************************************************************\n# Server configuration\n#*********************************************************************\n#服务器的接入IP。给客户端提供是${server.ip}和${http_port}。\n#客户端会从${http_port}端口获取到长链接端口。这个地址一定要改成客户端可以访问到的IP地址\n#（如果您部署云服务器上或者具有独立公网出口的服务器上，请改为对应的公网IP；如果您部署在在内网环境下，在内网使用，这个地方改成内网地址）\nserver.ip 192.168.1.81\n\n##原生客户端长链接端口\nport 1883\n\n##客户端短链接端口，客户端固定使用80端口，不要修改此端口。\nhttp_port 80\n\n#管理端口\nhttp.admin.port 18080\n\n##节点ID，当集群部署时，一定不能有重复。\nnode_id 1\n\n##绑定IP，不要打开，除非有特殊需求才可以打开\n#host 0.0.0.0\n\n##本地绑定端口\nlocal_port 80\n\n## 是否使用内置DB。0使用mysql；1使用h2db。\n## MySQL需要把事物隔离级别改成\"Read committed\"，使用命令来修改\"set global transaction_isolation='read-committed';\"，其他数据库默认已经是这个级别不用修改\nembed.db 1\n\n## 是否自动清理历史消息记录，当为true时，IM服务会定时扫描t_messages_x和t_user_messages_x表，清除掉3年前的历史消息。\n## 如果不开启自动清理，需要手动清理t_messages_x和t_user_messages_x表内的历史数据，保存数据不能超过3年。\n## 如果需要消息保存更长时间，可以把临近销毁的消息转储到别的数据库，客户端在拉取不到服务器消息时，再去转储的数据库拉取。\n## 使用mongodb时次开关无效（因为mongodb设置了消息过期时间，会自动清理，仅专业版支持mongodb）。\ndb.auto_clean_history_messages true\n\n## h2db数据库的路径，默认为程序目录下的，可以指定其他目录。如果使用MySQL，可以忽略此配置\nh2db.path ./h2db/wfchat\n\n##服务器管理接口密钥。如果修改此端口需要同步修改使用管理API的地方，比如应用服务。\nhttp.admin.secret_key 123456\n\n##服务器API接口参数是否检查时间。当设置为false时，所有的请求会检查时间的有效性；当设置为true时，可以在http.admin.secret_key保持不变的情况下，使用固定的服务API签名\n##nonce = \"76616\", timestamp = \"1558350862502\", sign = \"b98f9b0717f59febccf1440067a7f50d9b31bdde\"\n##这个地方上线前要改为false\nhttp.admin.no_check_time true\n\n##用来生产im token的私钥，只在服务器使用，客户端不用。正式使用时为了安全一定要修改这个值，切记切记\ntoken.key testim\n\n##token的过期时间，单位为毫秒，默认为无限期。如果需要设置无限期，客户端上一定需要加上token过期的处理。token过期的处理请参考文档的常见问题\n##token.expire_time 2592000000\n\n##客户端（目前只有android）的应用签名（一个应用最取第一个签名），如果有多个签名(多个客户端)，用英文逗号分开。获取签名方法请参考文档：https://docs.wildfirechat.cn/blogs/签名验证.html\n#connect.client_signature_list eNkezQ1g9OsnhfLSFUY1vzKDzhs=,xykezQ1g9OsnhfLSFUY1vzKDzhs=\n\n##是否拒绝空签名的android客户端， 默认为true。当有旧的客户端需要兼容时改成false，当所有都是新客户端时，改成true。\n#connect.reject_empty_signature true\n\n##是否使用AES256加密。默认客户端和服务器都是AES128加密，如果需要开启AES256，需要客户端和IM服务同时开通。\n#encrypt.use_aes256 true\n\n##当创建一个对象时（用户，群组，频道，机器人等），如果没有传入ID，野火会为这个对象生成一个ID。如果id.use_uuid为true，会使用uuid作为对象ID，否则会使用野火短ID，默认为false。\n## 短ID有个很大的风险是容易被人穷举进行攻击。建议用UUID。\nid.use_uuid true\n\n##首次登录，是否接收之前的历史消息。\n##0 不接收历史消息，只接收${message.compensate_time_limit}毫秒以内的消息，由于服务器没有保存已经收取记录，所以如果有超过${message.compensate_time_limit}毫秒之前未收取的消息也不会收取下拉；\n##1接收，会接收 message.max_queue 配置的条数的历史消息\nmessage.roaming 0\n\n## 消息补偿时限，当${message.roaming}为0时，会同步时限以内且小于${message.max_queue}的消息，默认时限为5分钟。当${message.roaming}为1时，会接收 message.max_queue 配置的条数的历史消息。\nmessage.compensate_time_limit 300000\n\n##是否开启拉取远程历史消息。如果为1，客户端在会话内如果本地消息读取完了，可以下拉继续加载在服务器上的该会话的消息；如果为0则不能。\nmessage.remote_history_message 0\n\n##服务器为每个用户缓存的消息数量。这个值改得太大，拉取消息时间变长，另外会占用大量内存。\nmessage.max_queue 1024\n\n##是否开启拉取聊天室远程历史消息。如果为1，可以下拉继续加载在服务器上的该聊天室的消息；如果为0则不能。默认为1\nmessage.chatroom_remote_history_message 1\n\n##是否禁止陌生人聊天\nmessage.disable_stranger_chat false\n\n##当禁止陌生人聊天时，允许聊天的用户id，比如管理员或者文件传输助手等。用户id以英文逗号分割。\nmessage.allow_stranger_chat_list admin,FireRobot,wfc_file_transfer\n\n##当禁止陌生人聊天时，允许聊天的线路。\n#message.allow_stranger_line 100,101\n\n##黑名单策略，0 发送失败，返回被拉黑的错误码；1 发送成功但消息被服务器直接丢弃\nmessage.blacklist.strategy 0\n\n##拉黑对方后，对方不能发送消息给你。这个开关确定拉黑对方后你还能不能给对方发送消息。\nmessage.blacklist.allow_send_to_black false\n\n##是否禁止服务器端消息搜索，该功能暂未实现。目前的影响是如果打开，则存储消息时不单独保存_searchable_content字段\nmessage.disable_remote_search  false\n\n##是否数据库中加密消息内容。注意这个开关在服务运行起来后不能改变了，避免读取数据库时无法恢复历史消息。\n##如果要避免数据库中明文存储消息内容，请打开这个开关和message.disable_remote_search开关\nmessage.encrypt_message_content false\n\n##允许客户端撤回用户自己发送的消息时限，单位是秒。0是不允许撤回；-1是无限制撤回。\n##Server API不受此限制，可以撤回任意时限内的消息\n##群组管理员或群主撤回群成员消息不受此限制，可以撤回任意时限内的消息。但管理员或群主撤回自己的消息还是需要准守此时间限制。\n##修改此参数需要同步修改客户端UI，客户端UI代码有判断撤回是否显示的逻辑。\nmessage.recall_time_limit 120\n\n##禁止群主/群管理员撤回群内消息，关闭时群主/群管理员可以撤回任意时间段内群内成员的消息。\nmessage.disable_group_manager_recall false\n\n##禁止客户端发送消息类型，消息类型以逗号分开，下面3个值为示例，可以删除。\n##一般用于重要类型消息，比如交易、充值等，禁止客户端发送，仅限于服务器发送，提高安全性。\n#message.forbidden_client_send_types 3999,4000,4001\n\n## 当禁止发送消息时，允许例外发送的消息。这种一般用户需要被动回应的消息。比如群中被禁言的用户，他无法主动发起音视频，但可以接听未被禁言用户的音视频\n## 因为音视频使用了消息作为信令，所以就需要允许发送音视频信令。如果开发了其它场景也需要被动回应消息，可以加在这里。\n## 黑名单时允许发送的消息类型\nmessage.blacklist_exception_types 401,402,403,404,405,407,408,410,411\n## 群禁言或者聊天室或者频道禁言时允许发送的消息类型\nmessage.group_mute_exception_types 401,402,403,404,405,407,408,410,411\n## 用户被全局禁言时允许发送的消息类型\nmessage.global_mute_exception_types 401,402,403,404,405,407,408,410,411\n\n## 离线用户推送过期天数，0是永不过期，建议配置为7天。\nmessage.push_expired_days 7\n\n## 当会话静音/全局静音/PC在线静音时，普通消息都不会有推送，如果有某些消息类型需要此时保持推送，可以配置到这里。此配置对消息免打扰时段无效。\n## 此配置只影响远程推送，需要客户端处理客户端在线且在后台收到此消息的处理，需要针对这些消息类型加上本地通知。\n## 强制推送消息的MessagePayload中pushContent和pushData至少要存在一个才可以推送。\n## 消息类型以英文逗号分割。\n#message.force_push_types 401,402\n\n## 群发消息(包括server api群发和全局频道群发)时，目标用户是否来自于t_user表。如果使用野火托管用户信息，请设置为true，否则设置为false。\nmessage.broadcast.target_from_user_table true\n\n## 消息转发功能开启时，开关是否不转发server api接口消息。\n## 当为true时，不转发server api发送的消息；当为false时，转发server api发送的消息。\nmessage.no_forward_admin_message false\n\n## 消息转发功能开启时，转发信息是否带上用户clientId和平台类型。\nmessage.forward_with_client_info false\n\n## 消息转发功能开启时，转发信息是否带上发送者的用户信息\nmessage.forward_with_sender_info false\n\n## 消息转发功能开启时，转发信息是否带上目标的信息，单聊时是对方用户信息，群聊时是群组信息，频道时是频道信息\nmessage.forward_with_target_info false\n\n## 允许发送单聊消息给被封禁用户\nmessage.allow_send_to_forbidden_user false\n\n## 机器人回调信息是否带上用户clientId和平台类型。\nrobot.callback_with_client_info false\n\n## 机器人回调信息是否带上发送者的用户信息\nrobot.callback_with_sender_info false\n\n## 机器人回调信息是否带上目标的信息，单聊时是对方用户信息，群聊时是群组信息，频道时是频道信息\nrobot.callback_with_target_info false\n\n## 是否允许@会话外的机器人。如果为true，单聊或者群聊时，可以@不在会话中的机器人。当机器人收到消息后，可以回复消息。\n## 如果为false，不能@不在会话中的机器人。机器人不在会话中时，也不能回复消息。\nrobot.mention_external_robot true\n\n## 机器人获取信息允许的字段，可以获取userId/displayName/portrait，其他需要这里配置允许。\n## 第一位(1)是name， 第二位(2)是mobile，第三(4)位是email，第四位(8)是address，第五位(16)是company，第六位(32)是extra，\n## 第七位(64)是updateDt，第八位(128)是gender，第九位(256)是social，第十位(512)是type。\n## 比如允许获取name和email就是5(1+4)，允许获取name和mobile和company和type就是531（1+2+16+512），允许全部是1023(1+2+...+512)\n#robot.get_user_info_mask 1023\n\n## 频道回调信息是否带上用户clientId和平台类型。\nchannel.callback_with_client_info false\n\n## 频道回调信息是否带上发送者的用户信息。\nchannel.callback_with_sender_info false\n\n## 频道回调信息是否带上频道信息\nchannel.callback_with_target_info false\n\n## 频道回调新方式，在新方式下，如果有callback地址就会总是回调客户端发送的消息（包括owner和订阅者）。automatic属性控制订阅者发送的消息是否发给owner， 0发，1不发。\n## 旧的方式是，automatic为0时，订阅者的消息发给owner，不转发消息到callback地址。为1时，把订阅者的消息转发给callback地址，不发给owner。\nchannel.new_callback_feature true\n\n##禁止搜索用户\nfriend.disable_search false\n\n##禁止按照昵称搜索用户。\nfriend.disable_nick_name_search false\n\n##禁止按照用户id搜索用户，默认为false。\nfriend.disable_user_id_search false\n\n##禁止发送好友邀请，通过server api添加好友不受此限制(force参数需要为true)\nfriend.disable_friend_request false\n\n##好友请求重复发送的间隔，单位是毫秒，默认是7天，0为无限长期限。\nfriend.repeat_request_duration 604800000\n\n##好友请求被拒绝后再次发送的间隔，单位是毫秒，默认是30天，0为不限制。不能小于friend.repeat_request_duration。\nfriend.reject_request_duration 2592000000\n\n##好友请求过期时间，单位是毫秒，默认是7天，0为无限长期限。\nfriend.request_expiration_duration 604800000\n\n##好友请求限制频率，一个用户24小时之内允许请求好友的次数，默认不限频。\nfriend.request_rate_limit 30\n\n##如果搜索电话号码，24小时内搜索错误号码几次就不再允许电话号码搜素。防止有人遍历搜索电话号码\nfriend.search_mobile_empty_rate_limit 5\n\n##如果搜索用户，24小时内搜索次数。防止有人遍历用户名或者用户ID乱加好友。另外可以禁止ID搜索friend.disable_user_id_search\nfriend.search_rate_limit 100\n\n##请求添加机器人为好友时，机器人是否自动接受，默认为true\nfriend.robot_auto_accept true\n\n## 聊天室观众空闲退出时间，单位为毫秒，默认为15分钟，0为永远不退出\nchatroom.participant_idle_time 900000\n\n## 用户向聊天室发送消息，自动加入聊天室\nchatroom.rejoin_when_active true\n\n## 当一个聊天室不存在时，如果有用户加入就自动创建\nchatroom.create_when_not_exist true\n\n## 一个用户同一时刻只能加入一个聊天室。\n## 当一个客户端加入一个聊天室时，如果这个客户端已经加入另外一个聊天室了，会自动退出之前的聊天室。\n## 当一个客户端加入一个聊天室时，如果这个用户的其他端已经加入一个聊天室了，kickoff_other_platform为true时会自动退出之前的聊天室，为false时会返回225的错误码。\n## 当自动退出聊天室时，客户端不会收到任何通知，只是不会再收到消息。\nchatroom.kickoff_other_platform true\n\n## 是否允许群主不受限制地撤回自己发送的消息。false可以${message.recall_time_limit}撤回自己的消息；true可以撤回任意时间自己的消息。默认为true。\ngroup.allow_owner_recall_self_msg true\n\n## 是否允许群管理员不受限制地撤回自己发送的消息。false可以${message.recall_time_limit}撤回自己的消息；true可以撤回任意时间自己的消息。默认为false。\ngroup.allow_manager_recall_self_msg false\n\n## 是否允许客户端发送操作群的自定义群通知消息\ngroup.allow_client_custom_operation_notification true\n\n## 是否允许机器人发送操作群的自定义群通知消息\ngroup.allow_robot_custom_operation_notification true\n\n## 当群成员退出或者被移除时，是否同时给管理员和相关人员发送显式通知消息。\n## 0 不发送，1 退群时发送，2 踢人时发送，3 退群和踢人时都发送。\ngroup.visible_quit_or_kickoff_notification 0\n\n## 禁止客户端群操作。第1位是禁止创建群组，第2位是禁止销毁群组，3位禁止加入群，4位禁止退出群，5位禁止邀请群成员，6位禁止移出群成员，7位禁止转移群，8位禁止设置群管理员，9位禁止白名单处理，10位禁止群禁言，11位禁止修改群组信息，12位禁止群成员禁言。\n## Server API不受此限制。\n#group.forbidden_client_operation 0xFFF\n\n## 是否禁止陌生人拉人入群，默认为false\ngroup.disable_stranger_invite false\n\n## 创建群组或者加人时。可能会有成员加入失败（黑名单，或者不允许陌生人拉入群）。当出现有成员失败时，如果此开关为关，操作会失败。\n## 如果此开关打开，操作会返回成功，另外在群里发送一条通知消息 XXX 拒绝加入群组。默认为开。\ngroup.add_member_allow_part_success true\n\n## 群组信息是否标记删除\ngroup.enable_mark_deletion true\n\n## 隐藏用户信息属性类型，2是性别，3是电话号码，4是邮箱，5是地址，6是公司信息，7是社交账号，8是Extra信息。当需要隐藏多个时以英文逗号分开;\n## 本配置是为了提高安全性，避免把对应信息同步到客户端，这样就能防止程序被破解从而拿到用户关键信息。仅对客户端有效，server api不受影响。\n## 注意，修改本配置不会对已经同步的信息产生影响。\n#user.hide_properties 3,4,5\n\n## 销毁用户时，用户信息会被清空，deleted字段设置为1，这个开关控制是否保留用户昵称，默认为true。\nuser.keep_display_name_when_destroy true\n\n## 销毁用户时deleted字段设置为1，这个开关控制是否保留其他信息，默认是false。\nuser.keep_full_info_when_destroy false\n\n## 销毁用户时，如果user.keep_full_info_when_destroy为true，会保留所有信息，这个开关控制是否保留这个用户信息的电话号码，默认为false。\n## 当保留所有信息且保留电话号码时，用户如果再注册会用到原来的UID，能够看到原来用户的消息，需要考虑一下是否让已删除用户再次注册登录看到之前的消息。\nuser.keep_mobile_when_destroy false\n\n## 销毁用户时是否保留归属于这个用户的所有消息记录，默认为false。\nuser.keep_messages_when_destroy false\n\n# 好友/好友请求/用户设置 这三类数据同步的最大条目数。之前是客户第一次登录时，会把所有的对应数据一次下载到客户端，但如果有特别多的信息，会导致无法同步到客户端，\n# 因此需要分段多次同步，此开关定义了每次同步的数据的条数。此需要客户端支持，客户端SDK在2021.5.25日后支持此功能。如果确认所有客户端都在这个日志之后才可以打开此设置。\n#sync.data_part_size 1000\n\n## 是否关闭api/version接口。api/version方法可以用来检查IM服务版本，上线确认无问题后，可以关掉这个接口。\n#http.close_api_version false\n\n#*********************************************************************\n# 限频配置\n#*********************************************************************\n##API接口限频设置，时间是10秒内允许的请求次数。\n##管理api频率限制，默认是10秒10000次。\nhttp.admin.rate_limit 10000\n##机器人api频率限制，默认是10秒1000次，按照机器人ID区分。\nhttp.robot.rate_limit 1000\n##频道api频率限制，默认是10秒1000次，按照频道ID区分。\nhttp.channel.rate_limit 1000\n\n##客户端请求频率限制，默认是5秒100次。通常情况下不要修改这个值。\nclient.request_rate_limit 100\n\n#*********************************************************************\n# Media server configuration\n#*********************************************************************\n##是否使用七牛云存储。1使用七牛；0使用内存文件服务器。默认的七牛账户信息不可用，请在七牛官网申请账户并配置\n##专业版另外支持阿里云存储和野火私有存储，关于野火私有存储请参考：https://github.com/wildfirechat/WF-minio\n##关于对象存储的详细信息请参考：https://docs.wildfirechat.cn/server/oss.html\nmedia.server.use_qiniu 0\n\n# qiniu media server configuration\nqiniu.server_url  http://up.qbox.me\nqiniu.access_key tU3vdBK5BL5j4N7jI5N5uZgq_HQDo170w5C9Amnn\nqiniu.secret_key YfQIJdgp5YGhwEw14vGpaD2HJZsuJldWtqens7i5\nqiniu.bucket_general_name media\nqiniu.bucket_general_domain http://pghnpyzos.bkt.clouddn.com\nqiniu.bucket_image_name media\nqiniu.bucket_image_domain http://pghnpyzos.bkt.clouddn.com\nqiniu.bucket_voice_name media\nqiniu.bucket_voice_domain http://pghnpyzos.bkt.clouddn.com\nqiniu.bucket_video_name media\nqiniu.bucket_video_domain http://pghnpyzos.bkt.clouddn.com\nqiniu.bucket_file_name media\nqiniu.bucket_file_domain http://pghnpyzos.bkt.clouddn.com\nqiniu.bucket_sticker_name media\nqiniu.bucket_sticker_domain http://pghnpyzos.bkt.clouddn.com\nqiniu.bucket_moments_name media\nqiniu.bucket_moments_domain http://pghnpyzos.bkt.clouddn.com\nqiniu.bucket_portrait_name storage\nqiniu.bucket_portrait_domain http://cdn2.wildfirechat.cn\nqiniu.bucket_favorite_name storage\nqiniu.bucket_favorite_domain http://cdn2.wildfirechat.cn\n## custom的桶是给客户预留的，客户可以上传自己的文件到这3个桶中，野火不会用到这几个桶。如果不需要，可以忽略这几个配置\nqiniu.bucket_custom1_name temp1\nqiniu.bucket_custom1_domain http://temp1.wildfirechat.cn\nqiniu.bucket_custom2_name temp2\nqiniu.bucket_custom2_domain http://temp2.wildfirechat.cn\nqiniu.bucket_custom3_name temp3\nqiniu.bucket_custom3_domain http://temp3.wildfirechat.cn\nqiniu.bucket_pan_name pan\nqiniu.bucket_pan_domain http://pan.wildfirechat.cn\n\n##媒体类型分类\n#Media_Type_GENERAL = 0,\n#Media_Type_IMAGE = 1,\n#Media_Type_VOICE = 2,\n#Media_Type_VIDEO = 3,\n#Media_Type_FILE = 4,\n#Media_Type_PORTRAIT = 5,\n#Media_Type_FAVORITE = 6,\n#Media_Type_STICKER = 7,\n#Media_Type_MOMENTS = 8\n\n# local media server configuration\n# 本地媒体服务器配置。\nlocal.media.storage.root media\n# 如果使用内置文件存储，文件上传后地址默认为 http://server.ip:http_port/fs/5/2021/03/27/08/filename。fs目录下按照类型存放文件，媒体类型见上面注释，比如5就是Media_Type_PORTRAIT，是客户端的头像文件。\n# 如果需要使用nginx添加https支持，请打开下面配置，这样客户端得到的文件地址为 https://example.com/media/fs/5/2021/03/27/08/filename。\n# 需要nginx把请求从https://example.com/media/fs 转到 http://server.ip:http_port/fs。注意需要带上所有header。\n# 尽管内置文件存储可以使用，但是我们还是建议使用专业级别的对象存储服务，社区版可以使用七牛，专业版另外支持阿里云和也是私有对象存储。详情请参考 https://docs.wildfirechat.cn/server/oss.html\n# local.media.storage.remote_server_url https://example.com/media\n\n# 是否支持任意多端登陆，为true时支持任意平台任意多个客户端同时登录；为false时每个平台只支持一个端登录，但不同平台可以同时登录。\n# Android/iOS为移动平台，windows/mac/linux为pc平台，web为web平台，小程序为小程序平台。\n# 建议使用false\nserver.multi_endpoint false\n\n## 是否支持PC多端登陆，当server.multi_endpoint为true时，此开关无意义，当为false时，可以单独打开PC端多端登录。\nserver.multi_pc_endpoint false\n\n## 是否支持PAD多端登陆，当server.multi_endpoint为true时，此开关无意义，当为false时，可以单独打开PAD端多端登录。\nserver.multi_pad_endpoint false\n\n## 是否支持可穿戴设备多端登陆，当server.multi_endpoint为true时，此开关无意义，当为false时，可以单独打开可穿戴设备多端登录。\nserver.multi_wearable_endpoint false\n\n## 是否支持TV设备多端登陆，当server.multi_endpoint为true时，此开关无意义，当为false时，可以单独打开TV多端登录。\nserver.multi_tv_endpoint false\n\n# 多平台连接状态通知（仅当multi_endpoint为false时有效），true时移动端可以收到pc或pad或web端登录的通知。\nserver.multi_platform_notification true\n\n# 当pc或者web在线时，手机是否默认静音，默认为true。注意仅影响默认值，用户可以手动切换是否静音。\n# 如果这里改为false，客户端那边需要同步修改pc在线默认通知状态，方法是client的setDefaultSilentWhenPcOnline函数。\nserver.mobile_default_silent_when_pc_online true\n\n## 客户端是否支持kickoff事件。当客户端被其他端登录踢出时，如果此开关为false时，客户端协议栈上报secret_mismatch。如果此开关为ture时，客户端协议栈上报kicked_off。\n## 客户端被踢时上报kicked_off是在2021.9.15之后才加上的。如果客户端协议栈全部为此日期之后的版本才可以打开此开关。\nserver.client_support_kickoff_event true\n\n#*********************************************************************\n# Push server configuration\n#*********************************************************************\n##推送服务项目地址：https://github.com/wildfirechat/push_server。\n##安卓推送服务器地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\npush.android.server.address http://localhost:8085/android/push\n\n##苹果推送服务器地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\npush.ios.server.address http://localhost:8085/ios/push\n\n##鸿蒙推送服务器地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\npush.harmony.server.address http://localhost:8085/harmony/push\n\n#*********************************************************************\n# 监控配置\n#*********************************************************************\n##异常事件产生回调\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#monitor.exception_event_address http://localhost:8888/im_exception_event/\n\n#*********************************************************************\n# 各种事件回调\n#*********************************************************************\n##用户在线状态事件回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#user.online_status_callback http://localhost:8888/im_event/user/online\n\n##用户信息变动事件回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#relation.relation_update_callback http://localhost:8888/im_event/user/relation\n\n##用户信息变动事件回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#user.user_info_update_callback http://localhost:8888/im_event/user/info\n\n##消息转发地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#message.forward.url http://localhost:8888/im_event/message\n##需要转发的消息类型，当有多个时以英文逗号分割，可以用-来指定区间，注意区间不能太大，因为要把区间内的所有数字都放入到Set中。如果转发所有消息，请注释掉配置或者设置为空\n#message.forward.types 1,2,3,5-10\n##需要转发的消息类型，当有多个时以英文逗号分割，可以用-来指定区间，注意区间不能太大，因为要把区间内的所有数字都放入到Set中。\n#message.forward.exclude_types 1,2,3,5-10\n\n##敏感消息转发地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#message.sensitive.forward.url http://localhost:8888/im_event/message\n\n##提醒消息转发地址，@全体用户和@某个用户消息会回调此地址。\n##此转发不受${message.forward.types}和${message.forward.exclude_types}限制。\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#message.mentionmsg.forward.url http://localhost:8888/im_event/message\n\n##撤回消息转发地址，当用户撤回消息会回调此地址。\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#message.recallmsg.forward.url http://localhost:8888/im_event/recall_message\n\n##设备信息转发地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#things_message.forward.url http://localhost:8888/im_event/things/message\n\n##群组信息变动事件回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#group.group_info_update_callback http://localhost:8888/im_event/group/info\n\n##群组信息变动事件回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#group.group_member_update_callback http://localhost:8888/im_event/group/member\n\n##频道信息变动回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#channel.channel_info_update_callback http://localhost:8888/im_event/channel/info\n\n##聊天室信息变动回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#chatroom.chatroom_info_update_callback http://localhost:8888/im_event/chatroom/info\n\n##聊天室成员变动回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#chatroom.chatroom_member_update_callback http://localhost:8888/im_event/chatroom/member\n\n#*********************************************************************\n# Sensitive configuration\n#*********************************************************************\n## 内置文本敏感词过滤处理方法，当命中敏感词后，消息会被记录到t_sensitive_messages表中，然后根据type类型做不同的处理，处理方式如下：\n## 0 发送失败；1 发送成功但消息被服务器直接丢弃；2 命中的敏感词被替换成***然后正常发送；3 正常发送。\n## 如果开启 message.sensitive.forward.url 配置，命中敏感词的消息还会被回调到这个地址\nsensitive.filter.type 2\n\n## 敏感词是否只处理消息。如果为true，只过滤消息；如果为false，会同时过滤用户昵称、群组名和群昵称。\n## 除了消息之外的信息只支持内部敏感词处理，不支持外置审核。\nsensitive.only_message false\n\n## 敏感词添加或者删除有2种方式，一种是通过Server API进行，这种方式会立即生效。另外一种方法是修改数据库，直接中数据库的t_sensitive_word表中处理\n## 修改数据库的方法不会立即生效，IM服务会2个小时重新加载一次敏感词。所以如果直接修改敏感词表，需要等2个小时，或者重启才能生效。\n\n## 如果内置敏感词库无法满足您的需求，可以开发部署独立敏感词审核服务。配置如下地址和消息类型，IM服务会把指定消息类型的消息回调到指定地址，内置的敏感词审核和敏感词转发功能就不再起作用了。\n## 审核服务返回状态码200表示继续发送，如果需要替换内容，返回状态码200并且内容为替换后的内容。返回403表示不允许发送。其它错误继续发送。\n## 独立审核服务地址，IM服务会post SendMessageData。如果需要修改消息内容，返回 MessagePayload。请参考应用服务中 \"/message/censor\" Mapping.\n#sensitive.remote_server_url http://192.168.3.202:8888/message/censor\n## 需要进行敏感词审核的消息类型，当有多个时以英文逗号分割\n#sensitive.remote_sensitive_message_type 1,2,3\n## 如果远程审核服务返回403，返回给发送端发送失败还是成功？实际上这个值影响发送响应是否等待审核结果，当为false时，消息发送给审核服务就立即返回成功给客户端。\n## 当为true时，消息发送给审核服务，等待审核结果，如果结果为继续发送就返回给客户端为成功，结果为禁止发送就返回失败给客户端。\n## 客户端操作的超时一般为10s左右，且考虑到复杂的网络情况，建议处理时间不要超过3s。建议这个值为false。\n#sensitive.remote_fail_when_matched false\n"
  },
  {
    "path": "broker/migrate/h2/V10__create_default_admin.sql",
    "content": "\ninsert into t_user (`_uid`,`_name`,`_display_name`,`_type`,`_dt`) values ('admin','admin','系统管理员',3,1);\n\n"
  },
  {
    "path": "broker/migrate/h2/V11__alter_device_token.sql",
    "content": "ALTER TABLE t_user_session MODIFY _token VARCHAR(240) DEFAULT NULL;\n"
  },
  {
    "path": "broker/migrate/h2/V12__add_group_control_columns.sql",
    "content": "alter table `t_group` add column `_mute` tinyint NOT NULL DEFAULT 0;\nalter table `t_group` add column `_join_type` tinyint NOT NULL DEFAULT 0;\nalter table `t_group` add column `_private_chat` tinyint NOT NULL DEFAULT 0;\nalter table `t_group` add column `_searchable` tinyint NOT NULL DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/h2/V13__create_settings_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_settings`;\nCREATE TABLE `t_settings` (\n  `id` int(11) NOT NULL PRIMARY KEY,\n  `value` varchar(64) NOT NULL,\n  `desc` varchar(128) NOT NULL\n);\n\n\ninsert into t_settings(`id`, `value`,`desc`) values (1, '3000', '最大群成员数量');\n"
  },
  {
    "path": "broker/migrate/h2/V14__add_id_for_sensitive_word.sql",
    "content": "alter table `t_sensitiveword` add column `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT;\n"
  },
  {
    "path": "broker/migrate/h2/V15__alter_voip_token_length.sql",
    "content": "alter table `t_user_session` modify column `_voip_token` varchar(240) DEFAULT '';\n\n\n"
  },
  {
    "path": "broker/migrate/h2/V16__add_friend_blocked.sql",
    "content": "alter table t_friend add column `_blacked` tinyint DEFAULT 0;\nupdate t_friend set `_blacked` = 1 where `_state` = 2;\n"
  },
  {
    "path": "broker/migrate/h2/V17__add_user_session_token_index.sql",
    "content": "alter table `t_user_session` ADD INDEX `session_token_index` ( `_token` );\n"
  },
  {
    "path": "broker/migrate/h2/V18__add_friend_request_index.sql",
    "content": "alter table t_friend_request add index `friend_request_uid_index` (`_friend_uid`);\n"
  },
  {
    "path": "broker/migrate/h2/V19__add_user_session_uid_index.sql",
    "content": "alter table `t_user_session` ADD INDEX `session_uid_index` ( `_uid` );\n"
  },
  {
    "path": "broker/migrate/h2/V1__baseline.sql",
    "content": ""
  },
  {
    "path": "broker/migrate/h2/V20__user_session_add_deleted.sql",
    "content": "alter table `t_user_session` add column `_deleted` tinyint DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/h2/V21__user_add_deleted.sql",
    "content": "alter table `t_user` add column `_deleted` tinyint DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/h2/V22__refactor_channel_status.sql",
    "content": "update t_channel set `_status` = 64 where `_status` = 3;\n"
  },
  {
    "path": "broker/migrate/h2/V23__alter_message_add_to_column.sql",
    "content": "alter table t_messages add column `_to` varchar(64) DEFAULT NULL;\n\n"
  },
  {
    "path": "broker/migrate/h2/V24__add_friend_extra.sql",
    "content": "alter table t_friend add column `_extra` TEXT DEFAULT NULL;\n"
  },
  {
    "path": "broker/migrate/h2/V25__create_chatroom_blacklist_manager.sql",
    "content": "\nDROP TABLE IF EXISTS `t_chatroom_blacklist`;\nCREATE TABLE `t_chatroom_blacklist` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_cid` varchar(64) NOT NULL,\n  `_uid` varchar(64) NOT NULL,\n  `_state` tinyint NOT NULL DEFAULT 0,\n  `_expired_time` bigint(20) NOT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `cr_bl_uid_index` (`_cid`,_uid)\n);\n\nDROP TABLE IF EXISTS `t_chatroom_manager`;\nCREATE TABLE `t_chatroom_manager` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_cid` varchar(64) NOT NULL,\n  `_uid` varchar(64) NOT NULL,\n  `_state` tinyint NOT NULL DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `cr_man_uid_index` (`_cid`,_uid)\n);\n\n"
  },
  {
    "path": "broker/migrate/h2/V26__add_user_messages_line.sql",
    "content": "alter table `t_user_messages` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages` ADD INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\n"
  },
  {
    "path": "broker/migrate/h2/V27__create_device_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_thing`;\n\nDROP TABLE IF EXISTS `t_device`;\nCREATE TABLE `t_device` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_token` varchar(64) DEFAULT '',\n  `_state` tinyint DEFAULT 0,\n  `_extra` TEXT DEFAULT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `device_uid_index` (`_uid` ASC)\n);\n\nDROP TABLE IF EXISTS `t_user_device`;\nCREATE TABLE `t_user_device` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_did` varchar(64) DEFAULT '',\n  INDEX `user_device_uid_index` (`_uid` ASC),\n  INDEX `user_device_did_index` (`_did` ASC)\n);\n"
  },
  {
    "path": "broker/migrate/h2/V28__add_session_user_type.sql",
    "content": "alter table t_user_session add column `_user_type` tinyint DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/h2/V29__create_receipt_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_read_report`;\nCREATE TABLE `t_read_report` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NULL,\n  `_type` tinyint NULL,\n  `_line` int(11) NULL,\n  `_target` varchar(64) NULL,\n  `_dt` bigint(20) NOT NULL DEFAULT 0,\n  INDEX `read_report_index` (`_uid`, `_type`, `_line`, `_target`)\n);\n\nDROP TABLE IF EXISTS `t_user_read_report`;\nCREATE TABLE `t_user_read_report` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_rid` int(11) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `user_read_report_index` (`_uid` DESC, `_seq` DESC),\n    UNIQUE INDEX `user_read_report_index2` (`_uid` DESC, `_rid` DESC)\n);\n\nDROP TABLE IF EXISTS `t_delivery_report`;\nCREATE TABLE `t_delivery_report` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `delivery_index` (`_uid`)\n);\n\n\nDROP TABLE IF EXISTS `t_user_delivery_report`;\nCREATE TABLE `t_user_delivery_report` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_rid` varchar(64) NOT NULL,\n  `_uid` varchar(64) NOT NULL,\n  `_seq` bigint(20) NOT NULL,\n  `_dt` DATETIME NOT NULL DEFAULT NOW(),\n  INDEX `user_delivery_index` (`_uid` DESC, `_seq` DESC),\n  UNIQUE INDEX `user_delivery_index2` (`_uid` DESC, `_rid` DESC)\n);\n"
  },
  {
    "path": "broker/migrate/h2/V2__create_table.sql",
    "content": "\n\nDROP TABLE IF EXISTS `t_group`;\nCREATE TABLE `t_group` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_gid` varchar(64) NOT NULL,\n  `_name` varchar(64) DEFAULT '',\n  `_portrait` varchar(1024) DEFAULT '',\n  `_owner` varchar(64) DEFAULT '',\n  `_type` tinyint NOT NULL DEFAULT 0,\n  `_extra` TEXT DEFAULT NULL,\n  `_dt` bigint(20) NOT NULL,\n  `_member_count` int(11) DEFAULT 0,\n  `_member_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `group_gid_index` (`_gid` ASC),\n  INDEX `group_name_index` (`_name` ASC)\n);\n\nDROP TABLE IF EXISTS `t_group_member`;\nCREATE TABLE `t_group_member` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_gid` varchar(64) NOT NULL,\n  `_mid` varchar(64) DEFAULT '',\n  `_alias` varchar(64) DEFAULT '',\n  `_type` tinyint DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `user_gid_mid_index` (`_gid`, `_mid`)\n);\n\nDROP TABLE IF EXISTS `t_user`;\n  CREATE TABLE `t_user` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_uid` varchar(64) NOT NULL,\n    `_name` varchar(64) DEFAULT '',\n    `_display_name` varchar(64) DEFAULT '',\n    `_gender` int(11) NOT NULL DEFAULT 0,\n    `_portrait` varchar(1024) DEFAULT '',\n    `_mobile` varchar(64) DEFAULT '',\n    `_email` varchar(64) DEFAULT '',\n    `_address` varchar(64) DEFAULT '',\n    `_company` varchar(64) DEFAULT '',\n    `_social` varchar(64) DEFAULT '',\n    `_passwd_md5` varchar(64) DEFAULT '',\n    `_salt` varchar(64) DEFAULT '',\n    `_extra` TEXT DEFAULT NULL,\n    `_type` tinyint DEFAULT 0,\n    `_dt` bigint(20) NOT NULL,\n    UNIQUE INDEX `user_uid_index` (`_uid` ASC),\n    UNIQUE INDEX `user_name_index` (`_name` ASC),\n    INDEX `user_display_name_index` (`_display_name` ASC),\n    INDEX `user_mobile_index` (`_mobile` ASC),\n    INDEX `user_email_index` (`_email` ASC)\n  );\n\nDROP TABLE IF EXISTS `t_user_status`;\nCREATE TABLE `t_user_status` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_status` int(11) NOT NULL DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `user_status_uid_index` (`_uid` ASC),\n);\n\nDROP TABLE IF EXISTS `t_friend_request`;\nCREATE TABLE `t_friend_request` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_friend_uid` varchar(64) NOT NULL,\n  `_reason` TEXT DEFAULT NULL,\n  `_status` tinyint NOT NULL DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  `_from_read_status` tinyint DEFAULT 0,\n  `_to_read_status` tinyint DEFAULT 0,\n  UNIQUE INDEX `fr_user_target_index` (`_uid` ASC, `_friend_uid` ASC)\n);\n\nDROP TABLE IF EXISTS `t_friend`;\nCREATE TABLE `t_friend` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_friend_uid` varchar(64) NOT NULL,\n  `_state` tinyint DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `f_user_target_index` (`_uid` ASC, `_friend_uid` ASC)\n);\n\nDROP TABLE IF EXISTS `t_user_setting`;\nCREATE TABLE `t_user_setting` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_scope` int NOT NULL,\n  `_key` varchar(64) NOT NULL,\n  `_value` varchar(4096) NOT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `user_setting_index` (`_uid` ASC, `_scope` ASC, `_key` ASC)\n);\n\nDROP TABLE IF EXISTS `t_id_generator`;\nCREATE TABLE `t_id_generator` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT\n)\nAUTO_INCREMENT = 3;\n\n\nDROP TABLE IF EXISTS `t_channel`;\nCREATE TABLE `t_channel` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_cid` varchar(64) NOT NULL,\n  `_name` varchar(64) DEFAULT '',\n  `_portrait` varchar(1024) DEFAULT '',\n  `_owner` varchar(64) DEFAULT '',\n  `_status` tinyint NOT NULL DEFAULT 0,\n  `_desc` TEXT DEFAULT NULL,\n  `_secret` varchar(64) DEFAULT '',\n  `_callback` varchar(1024) DEFAULT '',\n  `_automatic` tinyint NOT NULL DEFAULT 0,\n  `_extra` TEXT DEFAULT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `channel_cid_index` (`_cid` DESC),\n  INDEX `channel_name_index` (`_name` DESC)\n);\n\nDROP TABLE IF EXISTS `t_channel_listener`;\nCREATE TABLE `t_channel_listener` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_cid` varchar(64) NOT NULL,\n  `_mid` varchar(64) DEFAULT '',\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `channel_cid_mid_index` (`_cid`, `_mid`)\n);\n\n\nDROP TABLE IF EXISTS `t_user_session`;\nCREATE TABLE `t_user_session` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_cid` varchar(64) NOT NULL,\n  `_token` varchar(64) DEFAULT '',\n  `_voip_token` varchar(64) DEFAULT '',\n  `_secret` varchar(64) NOT NULL,\n  `_db_secret` varchar(64) NOT NULL,\n  `_platform` tinyint DEFAULT 0,\n  `_push_type` tinyint DEFAULT 0,\n  `_package_name` varchar(64) DEFAULT '',\n  `_device_name` varchar(64) DEFAULT '',\n  `_device_version` varchar(64) DEFAULT '',\n  `_phone_name` varchar(64) DEFAULT '',\n  `_language` varchar(64) DEFAULT '',\n  `_carrier_name` varchar(64) DEFAULT '',\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `session_uid_cid_index` (`_cid`, `_uid`)\n);\n\n\nDROP TABLE IF EXISTS `t_robot`;\nCREATE TABLE `t_robot` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_owner` varchar(64) DEFAULT '',\n  `_secret` varchar(64) DEFAULT '',\n  `_callback` varchar(1024) DEFAULT '',\n  `_state` tinyint DEFAULT 0,\n  `_extra` TEXT DEFAULT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `robot_uid_index` (`_uid` ASC),\n  INDEX `robot_owner_index` (`_owner` ASC)\n);\n\n\nDROP TABLE IF EXISTS `t_thing`;\nCREATE TABLE `t_thing` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_owner` varchar(64) DEFAULT '',\n  `_token` varchar(64) DEFAULT '',\n  `_extra` TEXT DEFAULT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `thing_uid_index` (`_uid` ASC),\n  INDEX `thing_owner_index` (`_owner` ASC)\n);\n\n\nDROP TABLE IF EXISTS `t_chatroom`;\nCREATE TABLE `t_chatroom` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_cid` varchar(64) NOT NULL,\n  `_title` varchar(64) DEFAULT '',\n  `_portrait` varchar(1024) DEFAULT '',\n  `_state` tinyint NOT NULL DEFAULT 0,\n  `_desc` TEXT DEFAULT NULL,\n  `_extra` TEXT DEFAULT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `chatroom_cid_index` (`_cid` DESC)\n);\n\nDROP TABLE IF EXISTS `t_sensitiveword`;\nCREATE TABLE `t_sensitiveword` (\n  `_word` TEXT DEFAULT NULL\n);\n\n"
  },
  {
    "path": "broker/migrate/h2/V30__add_group_member_create_dt.sql",
    "content": "alter table t_group_member add column `_create_dt`  bigint(20) DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/h2/V31__add_group_member_count_history_message.sql",
    "content": "alter table `t_group` add column `_history_message` tinyint NOT NULL DEFAULT 0;\nalter table `t_group` add column `_max_member_count` int(11) NOT NULL DEFAULT 2000;\n"
  },
  {
    "path": "broker/migrate/h2/V32__alter_setting_column_name.sql",
    "content": "alter table `t_settings` change column `value` `_value` varchar(64) NOT NULL;\nalter table `t_settings` change column `desc` `_desc` varchar(64) NOT NULL;\n"
  },
  {
    "path": "broker/migrate/h2/V33__alter_group_searchable_column.sql",
    "content": "alter table `t_group` modify column `_searchable` int(11) NOT NULL DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/h2/V34__create_files_table.sql",
    "content": "DROP TABLE IF EXISTS `t_file`;\nCREATE TABLE `t_file` (\n  `_mid` bigint(20) NOT NULL PRIMARY KEY,\n  `_from` varchar(64) NOT NULL,\n  `_type` tinyint NOT NULL DEFAULT 0,\n  `_target` varchar(64) NOT NULL,\n  `_line` int(11) NOT NULL DEFAULT 0,\n  `_name` varchar(128) DEFAULT '',\n  `_url` varchar(1024) NOT NULL DEFAULT '',\n  `_size` int(11) NOT NULL DEFAULT 0,\n  `_download_count` int(11) DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  INDEX `file_conv_index` (`_type`, `_line`, `_target`, `_mid`),\n  INDEX `file_user_index` (`_from`, `_mid`)\n);\n"
  },
  {
    "path": "broker/migrate/h2/V35__create_file_transfer_user.sql",
    "content": "\ninsert into t_user (`_uid`,`_name`,`_display_name`,`_portrait`,`_type`,`_dt`) values ('wfc_file_transfer','wfc_file_transfer','文件传输助手','https://static.wildfirechat.cn/wfc_file_transfer.png',1,1);\ninsert into t_robot (`_uid`,`_owner`,`_secret`,`_callback`,`_state`,`_dt`) values ('wfc_file_transfer', 'wfc_file_transfer', '', '', 0, 1);\n"
  },
  {
    "path": "broker/migrate/h2/V36__alter_channel_status_column.sql",
    "content": "alter table `t_channel` modify column `_status` int(11) NOT NULL DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/h2/V37__add_user_messages_mid_index.sql",
    "content": "alter table `t_user_messages` ADD INDEX `user_messages_mid_index` ( `_mid`);\n"
  },
  {
    "path": "broker/migrate/h2/V38__add_user_messages_conv_info.sql",
    "content": "alter table `t_user_messages` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages` add column `_target` varchar(129) NOT NULL DEFAULT '';\nalter table `t_user_messages` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n"
  },
  {
    "path": "broker/migrate/h2/V39__add_group_member_friend_request_extra.sql",
    "content": "alter table `t_group_member` add column `_extra` TEXT DEFAULT NULL;\nalter table `t_friend_request` add column `_extra` TEXT DEFAULT NULL;\n"
  },
  {
    "path": "broker/migrate/h2/V3__create_sharding_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_messages`;\nCREATE TABLE `t_messages` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_mid` bigint(20) NOT NULL,\n  `_from` varchar(64) NOT NULL,\n  `_type` tinyint NOT NULL DEFAULT 0,\n  `_target` varchar(64) NOT NULL,\n  `_line` int(11) NOT NULL DEFAULT 0,\n  `_data` BLOB NOT NULL,\n  `_searchable_key` TEXT DEFAULT NULL,\n  `_dt` DATETIME NOT NULL DEFAULT NOW(),\n  UNIQUE INDEX `message_uid_index` (`_mid` ASC)\n);\n\nDROP TABLE IF EXISTS `t_user_messages`;\nCREATE TABLE `t_user_messages` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    UNIQUE INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n);\n"
  },
  {
    "path": "broker/migrate/h2/V40__add_user_messages_cont_type.sql",
    "content": "alter table `t_user_messages` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n"
  },
  {
    "path": "broker/migrate/h2/V41__alter_user_setting_key_column.sql",
    "content": "alter table `t_user_setting` modify column `_key` varchar(128) NOT NULL;\n"
  },
  {
    "path": "broker/migrate/h2/V42__create_secret_chat_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_secret_chat`;\nCREATE TABLE `t_secret_chat` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_from` varchar(64) DEFAULT '',\n  `_from_cid` varchar(64) DEFAULT '',\n  `_to` varchar(64) DEFAULT '',\n  `_to_cid` varchar(64) DEFAULT '',\n  `_state` tinyint NOT NULL DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `secret_chat_uid_index` (`_uid` DESC)\n);\n"
  },
  {
    "path": "broker/migrate/h2/V43__add_message_table_conversation_index.sql",
    "content": "alter table `t_messages` add INDEX `messages_conv_index` ( `_type`, `_target`, `_line`);\n"
  },
  {
    "path": "broker/migrate/h2/V44__add_channel_listener_table_member_index.sql",
    "content": "alter table `t_channel_listener` add INDEX `channel_mid_index` ( `_mid`);\n"
  },
  {
    "path": "broker/migrate/h2/V45__add_channel_menu_column.sql",
    "content": "alter table `t_channel` add column `_menu` BLOB DEFAULT NULL;\n"
  },
  {
    "path": "broker/migrate/h2/V46__add_group_member_mid_index.sql",
    "content": "alter table `t_group_member` add INDEX `group_member_mid_index` (`_mid`);\n"
  },
  {
    "path": "broker/migrate/h2/V47__create_super_group.sql",
    "content": "alter table `t_group` add column `_super_group` tinyint NOT NULL DEFAULT 0;\n\nDROP TABLE IF EXISTS `t_group_messages`;\nCREATE TABLE `t_group_messages` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n);\n"
  },
  {
    "path": "broker/migrate/h2/V48__group_add_deleted_column.sql",
    "content": "alter table `t_group` add column `_deleted` tinyint NOT NULL DEFAULT 0;\n\n"
  },
  {
    "path": "broker/migrate/h2/V49__add_domain_table.sql",
    "content": "DROP TABLE IF EXISTS `t_domain`;\nCREATE TABLE `t_domain` (\n  `_domain_id` varchar(64) NOT NULL PRIMARY KEY,\n  `_name` varchar(64) NOT NULL,\n  `_desc` varchar(256) DEFAULT '',\n  `_email` varchar(64) DEFAULT '',\n  `_tel` varchar(64) DEFAULT '',\n  `_address` varchar(64) DEFAULT '',\n  `_extra` varchar(1024) DEFAULT '',\n  `_dt` bigint(20) NOT NULL\n);\n\nalter table `t_user` add column `_external` tinyint DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/h2/V4__create_default_chatroom.sql",
    "content": "\ninsert into t_chatroom (`_cid`, `_title`, `_desc`,`_dt`) values ('chatroom1','火信聊天室1','火信测试聊天室1，用来演示聊天室功能', 1);\n\ninsert into t_chatroom (`_cid`, `_title`, `_desc`,`_dt`) values ('chatroom2','火信聊天室2','火信测试聊天室2，用来演示聊天室功能', 1);\n\ninsert into t_chatroom (`_cid`, `_title`, `_desc`,`_dt`) values ('chatroom3','火信聊天室3','火信测试聊天室3，用来演示聊天室功能', 1);\n"
  },
  {
    "path": "broker/migrate/h2/V50__update_group_member_index.sql",
    "content": "CREATE INDEX `user_gid_dt_index` ON `t_group_member` (`_gid`, `_dt`);\n"
  },
  {
    "path": "broker/migrate/h2/V51__add_not_allow_name_setting.sql",
    "content": "insert into t_settings(`id`, `_value`,`_desc`) values (2, '文件传输助手,客服,官方', '禁止使用名称，如果有多个，以英文逗号隔开。直接修改数据库，不用重启IM服务');\n"
  },
  {
    "path": "broker/migrate/h2/V52__modify_message_target.sql",
    "content": "alter table `t_messages` modify column `_target` varchar(129) NOT NULL;\n"
  },
  {
    "path": "broker/migrate/h2/V53__session_add_ip_column.sql",
    "content": "ALTER TABLE `t_user_session` ADD COLUMN `_ip` varchar(40) DEFAULT '';\n"
  },
  {
    "path": "broker/migrate/h2/V54__add_group_member_index.sql",
    "content": "CREATE INDEX `user_gid_type_index` ON `t_group_member` (`_gid`, `_type`);\n"
  },
  {
    "path": "broker/migrate/h2/V55__create_conference_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_conference`;\nCREATE TABLE `t_conference` (\n  `_id` varchar(64) NOT NULL PRIMARY KEY,\n  `_des` varchar(64) NOT NULL,\n  `_pin` varchar(16) NOT NULL,\n  `_max_publishers` int(11) NOT NULL DEFAULT 0,\n  `_bitrate` int(11) NOT NULL DEFAULT 0,\n  `_advance` tinyint NOT NULL DEFAULT 0,\n  `_recording` tinyint NOT NULL DEFAULT 0,\n  `_create_dt` bigint(20) NOT NULL\n);\n\n"
  },
  {
    "path": "broker/migrate/h2/V56__create_join_group_request_table.sql",
    "content": "DROP TABLE IF EXISTS `t_join_group_request`;\nCREATE TABLE `t_join_group_request` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_gid` varchar(64) NOT NULL,\n  `_mid` varchar(64) NOT NULL,\n  `_request_uid` varchar(64) NOT NULL,\n  `_accept_uid` varchar(64) DEFAULT NULL,\n  `_reason` TEXT DEFAULT NULL,\n  `_extra` TEXT DEFAULT NULL,\n  `_status` tinyint NOT NULL DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  `_read_status` tinyint DEFAULT 0,\n  UNIQUE INDEX `join_group_request_key_index` (`_uid` DESC, `_gid` DESC, `_mid` DESC, `_request_uid` DESC),\n  INDEX `join_group_request_gm_index` (`_gid` DESC, `_mid` DESC),\n  INDEX `join_group_request_sync_index` (`_uid` DESC, `_dt` DESC)\n);\n"
  },
  {
    "path": "broker/migrate/h2/V57__create_friend_index.sql",
    "content": "alter table t_friend add index `friend_uid_index` (`_friend_uid`);\n"
  },
  {
    "path": "broker/migrate/h2/V5__create_default_robot.sql",
    "content": "\ninsert into t_user (`_uid`,`_name`,`_display_name`,`_portrait`,`_type`,`_dt`) values ('FireRobot','FireRobot','小火','http://cdn2.wildfirechat.cn/robot.png',1,1);\n\ninsert into t_robot (`_uid`,`_owner`,`_secret`,`_callback`,`_state`,`_dt`) values ('FireRobot', 'FireRobot', '123456', 'http://127.0.0.1:8883/robot/recvmsg', 0, 1);\n"
  },
  {
    "path": "broker/migrate/h2/V6__add_friend_alias.sql",
    "content": "\nalter table t_friend add column `_alias` varchar(64) DEFAULT NULL;\n"
  },
  {
    "path": "broker/migrate/h2/V7__add_createtime_user_group_table.sql",
    "content": "alter table t_user add column `_createTime` TIMESTAMP default CURRENT_TIMESTAMP;\nalter table t_group add column `_createTime` TIMESTAMP default CURRENT_TIMESTAMP;\n"
  },
  {
    "path": "broker/migrate/h2/V8__add_content_type_in_messages.sql",
    "content": "alter table `t_messages` add column `_content_type` int(11) NOT NULL DEFAULT '0';\n"
  },
  {
    "path": "broker/migrate/h2/V9__add_sensitive_messages.sql",
    "content": "\nDROP TABLE IF EXISTS `t_sensitive_messages`;\nCREATE TABLE `t_sensitive_messages` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_mid` bigint(20) NOT NULL,\n  `_from` varchar(64) NOT NULL,\n  `_type` tinyint NOT NULL DEFAULT 0,\n  `_target` varchar(64) NOT NULL,\n  `_line` int(11) NOT NULL DEFAULT 0,\n  `_data` BLOB NOT NULL,\n  `_searchable_key` TEXT DEFAULT NULL,\n  `_dt` DATETIME NOT NULL DEFAULT NOW(),\n  `_content_type` int(11) NOT NULL DEFAULT 0,\n  UNIQUE INDEX `sensitive_message_uid_index` (`_mid` ASC)\n);\n"
  },
  {
    "path": "broker/migrate/mysql/V10__create_default_admin.sql",
    "content": "\ninsert into t_user (`_uid`,`_name`,`_display_name`,`_type`,`_dt`) values ('admin','admin','系统管理员',3,1);\n\n"
  },
  {
    "path": "broker/migrate/mysql/V11__alter_device_token.sql",
    "content": "ALTER TABLE t_user_session MODIFY _token VARCHAR(240) DEFAULT NULL;\n"
  },
  {
    "path": "broker/migrate/mysql/V12__add_group_control_columns.sql",
    "content": "alter table `t_group` add column `_mute` tinyint NOT NULL DEFAULT 0;\nalter table `t_group` add column `_join_type` tinyint NOT NULL DEFAULT 0;\nalter table `t_group` add column `_private_chat` tinyint NOT NULL DEFAULT 0;\nalter table `t_group` add column `_searchable` tinyint NOT NULL DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/mysql/V13__create_session_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_session`;\nCREATE TABLE `t_session` (\n  `row_id` varchar(50) not null primary key,\n  `del_flag` tinyint(1) default 0 null,\n  `create_time` timestamp null,\n  `update_time` timestamp null,\n  `expire_time` timestamp null,\n  `user_id` int null,\n  constraint `t_session_pk_2` unique (`user_id`, `expire_time`)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n"
  },
  {
    "path": "broker/migrate/mysql/V14__alter_createtime_user_group_table.sql",
    "content": "alter table t_user MODIFY column `_createTime` DATETIME NOT NULL DEFAULT NOW();\nalter table t_group MODIFY column `_createTime` DATETIME NOT NULL DEFAULT NOW();\n"
  },
  {
    "path": "broker/migrate/mysql/V15__alter_session_table_time.sql",
    "content": "alter table t_session MODIFY column `create_time` DATETIME NOT NULL DEFAULT NOW();\nalter table t_session MODIFY column `update_time` DATETIME NOT NULL DEFAULT NOW();\nalter table t_session MODIFY column `expire_time` DATETIME NOT NULL DEFAULT NOW();\n\n"
  },
  {
    "path": "broker/migrate/mysql/V16__update_message_dt_gmt8.sql",
    "content": "update t_messages_0 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_1 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_2 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_3 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_4 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_5 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_6 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_7 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_8 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_9 set _dt = date_add(_dt, interval 8 hour);\n\nupdate t_messages_10 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_11 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_12 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_13 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_14 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_15 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_16 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_17 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_18 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_19 set _dt = date_add(_dt, interval 8 hour);\n\nupdate t_messages_20 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_21 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_22 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_23 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_24 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_25 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_26 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_27 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_28 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_29 set _dt = date_add(_dt, interval 8 hour);\n\n\nupdate t_messages_30 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_31 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_32 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_33 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_34 set _dt = date_add(_dt, interval 8 hour);\nupdate t_messages_35 set _dt = date_add(_dt, interval 8 hour);\n"
  },
  {
    "path": "broker/migrate/mysql/V17__add_default_sensitive_word.sql",
    "content": ""
  },
  {
    "path": "broker/migrate/mysql/V18__create_settings_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_settings`;\nCREATE TABLE `t_settings` (\n  `id` int(11) NOT NULL PRIMARY KEY,\n  `value` varchar(64) NOT NULL,\n  `desc` varchar(128) NOT NULL default \"\"\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\ninsert into t_settings(`id`, `value`,`desc`) values (1, \"3000\", \"最大群成员数量\");\n"
  },
  {
    "path": "broker/migrate/mysql/V19__add_id_for_sensitive_word.sql",
    "content": "alter table `t_sensitiveword` add column `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT;\n"
  },
  {
    "path": "broker/migrate/mysql/V1__baseline.sql",
    "content": ""
  },
  {
    "path": "broker/migrate/mysql/V20__alter_voip_token_length.sql",
    "content": "alter table `t_user_session` modify column `_voip_token` varchar(240) DEFAULT '';\n\n\n"
  },
  {
    "path": "broker/migrate/mysql/V21__add_friend_blocked.sql",
    "content": "alter table t_friend add column `_blacked` tinyint DEFAULT 0 COMMENT \"0, normal; 1, blacked\";\nupdate t_friend set `_blacked` = 1 where `_state` = 2;\n"
  },
  {
    "path": "broker/migrate/mysql/V22__add_user_session_token_index.sql",
    "content": "alter table `t_user_session` ADD INDEX `session_token_index` ( `_token` );\n"
  },
  {
    "path": "broker/migrate/mysql/V23__add_friend_request_index.sql",
    "content": "alter table t_friend_request add index `friend_request_uid_index` (`_friend_uid`);\n"
  },
  {
    "path": "broker/migrate/mysql/V24__add_user_session_uid_index.sql",
    "content": "alter table `t_user_session` ADD INDEX `session_uid_index` ( `_uid` );\n"
  },
  {
    "path": "broker/migrate/mysql/V25__user_session_add_deleted.sql",
    "content": "alter table `t_user_session` add column `_deleted` tinyint DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/mysql/V26__user_add_deleted.sql",
    "content": "alter table `t_user` add column `_deleted` tinyint DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/mysql/V27__refactor_channel_status.sql",
    "content": "update t_channel set `_status` = 64 where `_status` = 3;\n"
  },
  {
    "path": "broker/migrate/mysql/V28__alter_message_add_to_column.sql",
    "content": "alter table t_messages add column `_to` varchar(64) DEFAULT NULL;\n\nalter table t_messages_0 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_1 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_2 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_3 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_4 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_5 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_6 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_7 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_8 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_9 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_10 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_11 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_12 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_13 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_14 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_15 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_16 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_17 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_18 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_19 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_20 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_21 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_22 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_23 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_24 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_25 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_26 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_27 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_28 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_29 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_30 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_31 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_32 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_33 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_34 add column `_to` varchar(64) DEFAULT NULL;\nalter table t_messages_35 add column `_to` varchar(64) DEFAULT NULL;\n"
  },
  {
    "path": "broker/migrate/mysql/V29__add_friend_extra.sql",
    "content": "alter table t_friend add column `_extra` TEXT DEFAULT NULL;\n"
  },
  {
    "path": "broker/migrate/mysql/V2__create_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_messages`;\nCREATE TABLE `t_messages` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_mid` bigint(20) NOT NULL,\n  `_from` varchar(64) NOT NULL,\n  `_type` tinyint NOT NULL DEFAULT 0,\n  `_target` varchar(64) NOT NULL,\n  `_line` int(11) NOT NULL DEFAULT 0,\n  `_data` BLOB NOT NULL,\n  `_searchable_key` TEXT DEFAULT NULL,\n  `_dt` DATETIME NOT NULL,\n  UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages`;\nCREATE TABLE `t_user_messages` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_mid` bigint(20) NOT NULL,\n  `_uid` varchar(64) NOT NULL,\n  `_seq` bigint(20) NOT NULL,\n  `_dt` DATETIME NOT NULL DEFAULT NOW(),\n  INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_group`;\nCREATE TABLE `t_group` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_gid` varchar(64) NOT NULL,\n  `_name` varchar(64) DEFAULT '',\n  `_portrait` varchar(1024) DEFAULT '',\n  `_owner` varchar(64) DEFAULT '',\n  `_type` tinyint NOT NULL DEFAULT 0,\n  `_extra` TEXT DEFAULT NULL,\n  `_dt` bigint(20) NOT NULL,\n  `_member_count` int(11) DEFAULT 0,\n  `_member_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `group_gid_index` (`_gid` DESC),\n  INDEX `group_name_index` (`_name` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_group_member`;\nCREATE TABLE `t_group_member` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_gid` varchar(64) NOT NULL,\n  `_mid` varchar(64) DEFAULT '',\n  `_alias` varchar(64) DEFAULT '',\n  `_type` tinyint DEFAULT 0 COMMENT \"0普通成员；1，管理员；2，群主，与Owner相同\",\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `user_gid_mid_index` (`_gid`, `_mid`)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user`;\nCREATE TABLE `t_user` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_name` varchar(64) DEFAULT '',\n  `_display_name` varchar(64) DEFAULT '',\n  `_gender` int(11) NOT NULL DEFAULT 0,\n  `_portrait` varchar(1024) DEFAULT '',\n  `_mobile` varchar(64) DEFAULT '',\n  `_email` varchar(64) DEFAULT '',\n  `_address` varchar(64) DEFAULT '',\n  `_company` varchar(64) DEFAULT '',\n  `_social` varchar(64) DEFAULT '',\n  `_passwd_md5` varchar(64) DEFAULT '',\n  `_salt` varchar(64) DEFAULT '',\n  `_extra` TEXT DEFAULT NULL,\n  `_type` tinyint DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `user_uid_index` (`_uid` ASC),\n  UNIQUE INDEX `user_name_index` (`_name` ASC),\n  INDEX `user_display_name_index` (`_display_name` ASC),\n  INDEX `user_mobile_index` (`_mobile` ASC),\n  INDEX `user_email_index` (`_email` ASC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_status`;\nCREATE TABLE `t_user_status` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_status` int(11) NOT NULL DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `user_status_uid_index` (`_uid` ASC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_friend_request`;\nCREATE TABLE `t_friend_request` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_friend_uid` varchar(64) NOT NULL,\n  `_reason` TEXT DEFAULT NULL,\n  `_status` tinyint NOT NULL DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  `_from_read_status` tinyint DEFAULT 0,\n  `_to_read_status` tinyint DEFAULT 0,\n  UNIQUE INDEX `fr_user_target_index` (`_uid` ASC, `_friend_uid` ASC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_friend`;\nCREATE TABLE `t_friend` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_friend_uid` varchar(64) NOT NULL,\n  `_state` tinyint DEFAULT 0 COMMENT \"0, normal; 1, deleted; 2, blacked\",\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `f_user_target_index` (`_uid` ASC, `_friend_uid` ASC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_setting`;\nCREATE TABLE `t_user_setting` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_scope` int NOT NULL,\n  `_key` varchar(64) NOT NULL,\n  `_value` varchar(4096) NOT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `user_setting_index` (`_uid` ASC, `_scope` ASC, `_key` ASC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_id_generator`;\nCREATE TABLE `t_id_generator` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci\nAUTO_INCREMENT = 3;\n\nDROP TABLE IF EXISTS `t_channel`;\nCREATE TABLE `t_channel` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_cid` varchar(64) NOT NULL,\n  `_name` varchar(64) DEFAULT '',\n  `_portrait` varchar(1024) DEFAULT '',\n  `_owner` varchar(64) DEFAULT '',\n  `_status` tinyint NOT NULL DEFAULT 0,\n  `_desc` TEXT DEFAULT NULL,\n  `_secret` varchar(64) DEFAULT '',\n  `_callback` varchar(1024) DEFAULT '',\n  `_extra` TEXT DEFAULT NULL,\n  `_automatic` tinyint NOT NULL DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `channel_cid_index` (`_cid` DESC),\n  INDEX `channel_name_index` (`_name` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_channel_listener`;\nCREATE TABLE `t_channel_listener` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_cid` varchar(64) NOT NULL,\n  `_mid` varchar(64) DEFAULT '',\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `channel_cid_mid_index` (`_cid`, `_mid`)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_session`;\nCREATE TABLE `t_user_session` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_cid` varchar(64) NOT NULL,\n  `_token` varchar(64) DEFAULT '',\n  `_voip_token` varchar(64) DEFAULT '',\n  `_secret` varchar(64) NOT NULL,\n  `_db_secret` varchar(64) NOT NULL,\n  `_platform` tinyint DEFAULT 0,\n  `_push_type` tinyint DEFAULT 0,\n  `_package_name` varchar(64) DEFAULT '',\n  `_device_name` varchar(64) DEFAULT '',\n  `_device_version` varchar(64) DEFAULT '',\n  `_phone_name` varchar(64) DEFAULT '',\n  `_language` varchar(64) DEFAULT '',\n  `_carrier_name` varchar(64) DEFAULT '',\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `session_uid_cid_index` (`_cid`, `_uid`)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_robot`;\nCREATE TABLE `t_robot` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_owner` varchar(64) DEFAULT '',\n  `_secret` varchar(64) DEFAULT '',\n  `_callback` varchar(1024) DEFAULT '',\n  `_state` tinyint DEFAULT 0,\n  `_extra` TEXT DEFAULT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `robot_uid_index` (`_uid` ASC),\n  INDEX `robot_owner_index` (`_owner` ASC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_thing`;\nCREATE TABLE `t_thing` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_owner` varchar(64) DEFAULT '',\n  `_token` varchar(64) DEFAULT '',\n  `_state` tinyint DEFAULT 0,\n  `_extra` TEXT DEFAULT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `thing_uid_index` (`_uid` ASC),\n  INDEX `thing_owner_index` (`_owner` ASC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_chatroom`;\nCREATE TABLE `t_chatroom` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_cid` varchar(64) NOT NULL,\n  `_title` varchar(64) DEFAULT '',\n  `_portrait` varchar(1024) DEFAULT '',\n  `_state` tinyint NOT NULL DEFAULT 0,\n  `_desc` TEXT DEFAULT NULL,\n  `_extra` TEXT DEFAULT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `chatroom_cid_index` (`_cid` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_sensitiveword`;\nCREATE TABLE `t_sensitiveword` (\n  `_word` TEXT DEFAULT NULL\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n"
  },
  {
    "path": "broker/migrate/mysql/V30__create_chatroom_blacklist_manager.sql",
    "content": "\nDROP TABLE IF EXISTS `t_chatroom_blacklist`;\nCREATE TABLE `t_chatroom_blacklist` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_cid` varchar(64) NOT NULL,\n  `_uid` varchar(64) NOT NULL,\n  `_state` tinyint NOT NULL DEFAULT 0,\n  `_expired_time` bigint(20) NOT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `cr_bl_uid_index` (`_cid`,_uid)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_chatroom_manager`;\nCREATE TABLE `t_chatroom_manager` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_cid` varchar(64) NOT NULL,\n  `_uid` varchar(64) NOT NULL,\n  `_state` tinyint NOT NULL DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `cr_man_uid_index` (`_cid`,_uid)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\n\n"
  },
  {
    "path": "broker/migrate/mysql/V31__add_user_messages_line.sql",
    "content": "alter table `t_user_messages` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_0` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_1` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_2` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_3` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_4` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_5` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_6` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_7` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_8` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_9` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_10` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_11` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_12` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_13` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_14` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_15` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_16` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_17` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_18` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_19` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_20` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_21` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_22` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_23` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_24` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_25` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_26` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_27` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_28` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_29` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_30` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_31` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_32` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_33` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_34` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_35` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_36` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_37` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_38` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_39` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_40` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_41` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_42` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_43` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_44` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_45` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_46` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_47` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_48` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_49` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_50` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_51` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_52` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_53` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_54` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_55` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_56` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_57` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_58` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_59` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_60` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_61` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_62` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_63` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_64` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_65` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_66` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_67` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_68` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_69` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_70` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_71` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_72` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_73` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_74` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_75` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_76` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_77` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_78` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_79` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_80` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_81` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_82` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_83` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_84` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_85` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_86` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_87` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_88` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_89` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_90` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_91` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_92` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_93` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_94` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_95` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_96` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_97` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_98` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_99` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_100` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_101` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_102` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_103` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_104` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_105` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_106` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_107` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_108` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_109` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_110` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_111` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_112` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_113` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_114` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_115` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_116` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_117` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_118` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_119` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_120` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_121` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_122` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_123` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_124` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_125` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_126` add column `_line` int(11) NOT NULL DEFAULT 0;\nalter table `t_user_messages_127` add column `_line` int(11) NOT NULL DEFAULT 0;\n\n\nalter table `t_user_messages` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_0` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_1` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_2` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_3` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_4` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_5` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_6` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_7` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_8` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_9` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_10` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_11` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_12` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_13` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_14` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_15` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_16` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_17` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_18` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_19` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_20` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_21` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_22` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_23` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_24` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_25` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_26` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_27` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_28` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_29` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_30` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_31` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_32` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_33` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_34` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_35` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_36` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_37` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_38` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_39` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_40` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_41` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_42` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_43` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_44` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_45` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_46` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_47` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_48` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_49` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_50` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_51` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_52` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_53` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_54` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_55` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_56` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_57` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_58` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_59` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_60` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_61` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_62` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_63` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_64` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_65` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_66` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_67` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_68` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_69` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_70` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_71` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_72` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_73` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_74` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_75` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_76` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_77` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_78` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_79` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_80` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_81` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_82` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_83` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_84` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_85` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_86` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_87` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_88` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_89` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_90` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_91` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_92` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_93` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_94` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_95` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_96` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_97` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_98` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_99` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_100` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_101` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_102` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_103` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_104` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_105` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_106` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_107` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_108` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_109` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_110` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_111` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_112` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_113` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_114` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_115` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_116` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_117` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_118` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_119` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_120` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_121` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_122` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_123` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_124` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_125` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_126` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\nalter table `t_user_messages_127` add INDEX `message_mid_line_uid_index` ( `_uid` DESC, `_line` DESC, `_mid` DESC );\n"
  },
  {
    "path": "broker/migrate/mysql/V32__create_device_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_thing`;\n\nDROP TABLE IF EXISTS `t_device`;\nCREATE TABLE `t_device` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_token` varchar(64) DEFAULT '',\n  `_state` tinyint DEFAULT 0,\n  `_extra` TEXT DEFAULT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `device_uid_index` (`_uid` ASC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_device`;\nCREATE TABLE `t_user_device` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_did` varchar(64) DEFAULT '',\n  UNIQUE INDEX `user_device_uid_index` (`_uid` ASC, `_did` ASC),\n  INDEX `user_device_did_index` (`_did` ASC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n"
  },
  {
    "path": "broker/migrate/mysql/V33__add_session_user_type.sql",
    "content": "alter table t_user_session add column `_user_type` tinyint DEFAULT 0 COMMENT \"0, normal user; 1, robot; 2, device;\";\n"
  },
  {
    "path": "broker/migrate/mysql/V34__create_receipt_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_read_report`;\nCREATE TABLE `t_read_report` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NULL,\n  `_type` tinyint NULL,\n  `_line` int(11) NULL,\n  `_target` varchar(64) NULL,\n  `_dt` bigint(20) NOT NULL DEFAULT 0,\n  INDEX `read_report_index` (`_uid`, `_type`, `_line`, `_target`)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_read_report`;\nCREATE TABLE `t_user_read_report` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_rid` int(11) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `user_read_report_index` (`_uid` DESC, `_seq` DESC),\n    UNIQUE INDEX `user_read_report_index2` (`_uid` DESC, `_rid` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_delivery_report`;\nCREATE TABLE `t_delivery_report` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `delivery_index` (`_uid`)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_delivery_report`;\nCREATE TABLE `t_user_delivery_report` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_rid` varchar(64) NOT NULL,\n  `_uid` varchar(64) NOT NULL,\n  `_seq` bigint(20) NOT NULL,\n  `_dt` DATETIME NOT NULL DEFAULT NOW(),\n  INDEX `user_delivery_index` (`_uid` DESC, `_seq` DESC),\n  UNIQUE INDEX `user_delivery_index2` (`_uid` DESC, `_rid` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n"
  },
  {
    "path": "broker/migrate/mysql/V35__add_group_member_create_dt.sql",
    "content": "alter table t_group_member add column `_create_dt`  bigint(20) DEFAULT 0, COMMENT \"group member create time\";\n"
  },
  {
    "path": "broker/migrate/mysql/V36__add_group_member_count_history_message.sql",
    "content": "alter table `t_group` add column `_history_message` tinyint NOT NULL DEFAULT 0, COMMENT \"new group member can load group history messages\";\nalter table `t_group` add column `_max_member_count` int(11) NOT NULL DEFAULT 2000, COMMENT \"max group member count\";\n"
  },
  {
    "path": "broker/migrate/mysql/V37__alter_setting_column_name.sql",
    "content": "alter table `t_settings` change column `value` `_value` varchar(64) NOT NULL;\nalter table `t_settings` change column `desc` `_desc` varchar(64) NOT NULL;\n"
  },
  {
    "path": "broker/migrate/mysql/V38__alter_group_searchable_column.sql",
    "content": "alter table `t_group` modify column `_searchable` int(11) NOT NULL DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/mysql/V39__create_files_table.sql",
    "content": "DROP TABLE IF EXISTS `t_file`;\nCREATE TABLE `t_file` (\n  `_mid` bigint(20) NOT NULL PRIMARY KEY,\n  `_from` varchar(64) NOT NULL,\n  `_type` tinyint NOT NULL DEFAULT 0,\n  `_target` varchar(64) NOT NULL,\n  `_line` int(11) NOT NULL DEFAULT 0,\n  `_name` varchar(128) DEFAULT '',\n  `_url` varchar(1024) NOT NULL DEFAULT '',\n  `_size` int(11) NOT NULL DEFAULT 0,\n  `_download_count` int(11) DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  INDEX `file_conv_index` (`_type`, `_line`, `_target`, `_mid`),\n  INDEX `file_user_index` (`_from`, `_mid`)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n"
  },
  {
    "path": "broker/migrate/mysql/V3__create_sharding_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_messages_0`;\nCREATE TABLE `t_messages_0` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_1`;\nCREATE TABLE `t_messages_1` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_2`;\nCREATE TABLE `t_messages_2` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_messages_3`;\nCREATE TABLE `t_messages_3` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_4`;\nCREATE TABLE `t_messages_4` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_5`;\nCREATE TABLE `t_messages_5` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_messages_6`;\nCREATE TABLE `t_messages_6` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_7`;\nCREATE TABLE `t_messages_7` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_8`;\nCREATE TABLE `t_messages_8` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_messages_9`;\nCREATE TABLE `t_messages_9` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_10`;\nCREATE TABLE `t_messages_10` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_11`;\nCREATE TABLE `t_messages_11` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_messages_12`;\nCREATE TABLE `t_messages_12` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_13`;\nCREATE TABLE `t_messages_13` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_14`;\nCREATE TABLE `t_messages_14` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_messages_15`;\nCREATE TABLE `t_messages_15` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_16`;\nCREATE TABLE `t_messages_16` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_17`;\nCREATE TABLE `t_messages_17` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_messages_18`;\nCREATE TABLE `t_messages_18` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_19`;\nCREATE TABLE `t_messages_19` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_20`;\nCREATE TABLE `t_messages_20` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_messages_21`;\nCREATE TABLE `t_messages_21` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_22`;\nCREATE TABLE `t_messages_22` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_23`;\nCREATE TABLE `t_messages_23` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_messages_24`;\nCREATE TABLE `t_messages_24` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_25`;\nCREATE TABLE `t_messages_25` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_26`;\nCREATE TABLE `t_messages_26` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_messages_27`;\nCREATE TABLE `t_messages_27` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_28`;\nCREATE TABLE `t_messages_28` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_29`;\nCREATE TABLE `t_messages_29` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_messages_30`;\nCREATE TABLE `t_messages_30` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_31`;\nCREATE TABLE `t_messages_31` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_32`;\nCREATE TABLE `t_messages_32` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_messages_33`;\nCREATE TABLE `t_messages_33` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_34`;\nCREATE TABLE `t_messages_34` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_messages_35`;\nCREATE TABLE `t_messages_35` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    UNIQUE INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_0`;\nCREATE TABLE `t_user_messages_0` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_1`;\nCREATE TABLE `t_user_messages_1` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_2`;\nCREATE TABLE `t_user_messages_2` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_3`;\nCREATE TABLE `t_user_messages_3` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_4`;\nCREATE TABLE `t_user_messages_4` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_5`;\nCREATE TABLE `t_user_messages_5` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_6`;\nCREATE TABLE `t_user_messages_6` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_7`;\nCREATE TABLE `t_user_messages_7` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_8`;\nCREATE TABLE `t_user_messages_8` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_9`;\nCREATE TABLE `t_user_messages_9` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_10`;\nCREATE TABLE `t_user_messages_10` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_11`;\nCREATE TABLE `t_user_messages_11` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_12`;\nCREATE TABLE `t_user_messages_12` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_13`;\nCREATE TABLE `t_user_messages_13` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_14`;\nCREATE TABLE `t_user_messages_14` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_15`;\nCREATE TABLE `t_user_messages_15` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_16`;\nCREATE TABLE `t_user_messages_16` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_17`;\nCREATE TABLE `t_user_messages_17` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_18`;\nCREATE TABLE `t_user_messages_18` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_19`;\nCREATE TABLE `t_user_messages_19` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_20`;\nCREATE TABLE `t_user_messages_20` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_21`;\nCREATE TABLE `t_user_messages_21` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_22`;\nCREATE TABLE `t_user_messages_22` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_23`;\nCREATE TABLE `t_user_messages_23` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_24`;\nCREATE TABLE `t_user_messages_24` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_25`;\nCREATE TABLE `t_user_messages_25` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_26`;\nCREATE TABLE `t_user_messages_26` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_27`;\nCREATE TABLE `t_user_messages_27` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_28`;\nCREATE TABLE `t_user_messages_28` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_29`;\nCREATE TABLE `t_user_messages_29` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_30`;\nCREATE TABLE `t_user_messages_30` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_31`;\nCREATE TABLE `t_user_messages_31` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_32`;\nCREATE TABLE `t_user_messages_32` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_33`;\nCREATE TABLE `t_user_messages_33` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_34`;\nCREATE TABLE `t_user_messages_34` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_35`;\nCREATE TABLE `t_user_messages_35` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_36`;\nCREATE TABLE `t_user_messages_36` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_37`;\nCREATE TABLE `t_user_messages_37` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_38`;\nCREATE TABLE `t_user_messages_38` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_39`;\nCREATE TABLE `t_user_messages_39` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_40`;\nCREATE TABLE `t_user_messages_40` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_41`;\nCREATE TABLE `t_user_messages_41` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_42`;\nCREATE TABLE `t_user_messages_42` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_43`;\nCREATE TABLE `t_user_messages_43` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_44`;\nCREATE TABLE `t_user_messages_44` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_45`;\nCREATE TABLE `t_user_messages_45` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_46`;\nCREATE TABLE `t_user_messages_46` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_47`;\nCREATE TABLE `t_user_messages_47` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_48`;\nCREATE TABLE `t_user_messages_48` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_49`;\nCREATE TABLE `t_user_messages_49` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_50`;\nCREATE TABLE `t_user_messages_50` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_51`;\nCREATE TABLE `t_user_messages_51` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_52`;\nCREATE TABLE `t_user_messages_52` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_53`;\nCREATE TABLE `t_user_messages_53` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_54`;\nCREATE TABLE `t_user_messages_54` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_55`;\nCREATE TABLE `t_user_messages_55` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_56`;\nCREATE TABLE `t_user_messages_56` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_57`;\nCREATE TABLE `t_user_messages_57` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_58`;\nCREATE TABLE `t_user_messages_58` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_59`;\nCREATE TABLE `t_user_messages_59` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_60`;\nCREATE TABLE `t_user_messages_60` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_61`;\nCREATE TABLE `t_user_messages_61` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_62`;\nCREATE TABLE `t_user_messages_62` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_63`;\nCREATE TABLE `t_user_messages_63` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_64`;\nCREATE TABLE `t_user_messages_64` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_65`;\nCREATE TABLE `t_user_messages_65` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_66`;\nCREATE TABLE `t_user_messages_66` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_67`;\nCREATE TABLE `t_user_messages_67` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_68`;\nCREATE TABLE `t_user_messages_68` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_69`;\nCREATE TABLE `t_user_messages_69` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_70`;\nCREATE TABLE `t_user_messages_70` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_71`;\nCREATE TABLE `t_user_messages_71` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_72`;\nCREATE TABLE `t_user_messages_72` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_73`;\nCREATE TABLE `t_user_messages_73` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_74`;\nCREATE TABLE `t_user_messages_74` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_75`;\nCREATE TABLE `t_user_messages_75` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_76`;\nCREATE TABLE `t_user_messages_76` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_77`;\nCREATE TABLE `t_user_messages_77` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_78`;\nCREATE TABLE `t_user_messages_78` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_79`;\nCREATE TABLE `t_user_messages_79` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_80`;\nCREATE TABLE `t_user_messages_80` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_81`;\nCREATE TABLE `t_user_messages_81` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_82`;\nCREATE TABLE `t_user_messages_82` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_83`;\nCREATE TABLE `t_user_messages_83` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_84`;\nCREATE TABLE `t_user_messages_84` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_85`;\nCREATE TABLE `t_user_messages_85` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_86`;\nCREATE TABLE `t_user_messages_86` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_87`;\nCREATE TABLE `t_user_messages_87` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_88`;\nCREATE TABLE `t_user_messages_88` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_89`;\nCREATE TABLE `t_user_messages_89` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_90`;\nCREATE TABLE `t_user_messages_90` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_91`;\nCREATE TABLE `t_user_messages_91` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_92`;\nCREATE TABLE `t_user_messages_92` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_93`;\nCREATE TABLE `t_user_messages_93` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_94`;\nCREATE TABLE `t_user_messages_94` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_95`;\nCREATE TABLE `t_user_messages_95` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_96`;\nCREATE TABLE `t_user_messages_96` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_97`;\nCREATE TABLE `t_user_messages_97` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_98`;\nCREATE TABLE `t_user_messages_98` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_99`;\nCREATE TABLE `t_user_messages_99` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_100`;\nCREATE TABLE `t_user_messages_100` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_101`;\nCREATE TABLE `t_user_messages_101` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_102`;\nCREATE TABLE `t_user_messages_102` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_103`;\nCREATE TABLE `t_user_messages_103` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_104`;\nCREATE TABLE `t_user_messages_104` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_105`;\nCREATE TABLE `t_user_messages_105` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_106`;\nCREATE TABLE `t_user_messages_106` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_107`;\nCREATE TABLE `t_user_messages_107` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_108`;\nCREATE TABLE `t_user_messages_108` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_109`;\nCREATE TABLE `t_user_messages_109` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_110`;\nCREATE TABLE `t_user_messages_110` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_111`;\nCREATE TABLE `t_user_messages_111` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_112`;\nCREATE TABLE `t_user_messages_112` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_113`;\nCREATE TABLE `t_user_messages_113` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_114`;\nCREATE TABLE `t_user_messages_114` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_115`;\nCREATE TABLE `t_user_messages_115` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_116`;\nCREATE TABLE `t_user_messages_116` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_117`;\nCREATE TABLE `t_user_messages_117` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_118`;\nCREATE TABLE `t_user_messages_118` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_119`;\nCREATE TABLE `t_user_messages_119` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_120`;\nCREATE TABLE `t_user_messages_120` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_121`;\nCREATE TABLE `t_user_messages_121` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_122`;\nCREATE TABLE `t_user_messages_122` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_123`;\nCREATE TABLE `t_user_messages_123` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_124`;\nCREATE TABLE `t_user_messages_124` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_125`;\nCREATE TABLE `t_user_messages_125` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nDROP TABLE IF EXISTS `t_user_messages_126`;\nCREATE TABLE `t_user_messages_126` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nDROP TABLE IF EXISTS `t_user_messages_127`;\nCREATE TABLE `t_user_messages_127` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_uid` varchar(64) NOT NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_dt` DATETIME NOT NULL DEFAULT NOW(),\n    INDEX `message_seq_uid_index` (`_uid` DESC, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n"
  },
  {
    "path": "broker/migrate/mysql/V40__create_file_transfer_user.sql",
    "content": "\ninsert into t_user (`_uid`,`_name`,`_display_name`,`_portrait`,`_type`,`_dt`) values ('wfc_file_transfer','wfc_file_transfer','文件传输助手','https://static.wildfirechat.cn/wfc_file_transfer.png',1,1);\ninsert into t_robot (`_uid`,`_owner`,`_secret`,`_callback`,`_state`,`_dt`) values ('wfc_file_transfer', 'wfc_file_transfer', '', '', 0, 1);\n"
  },
  {
    "path": "broker/migrate/mysql/V41__alter_channel_status_column.sql",
    "content": "alter table `t_channel` modify column `_status` int(11) NOT NULL DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/mysql/V42__add_user_messages_mid_index.sql",
    "content": "alter table `t_user_messages` add INDEX `user_messages_mid_index` ( `_mid` );\nalter table `t_user_messages_0` add INDEX `user_messages0_mid_index` ( `_mid` );\nalter table `t_user_messages_1` add INDEX `user_messages1_mid_index` ( `_mid` );\nalter table `t_user_messages_2` add INDEX `user_messages2_mid_index` ( `_mid` );\nalter table `t_user_messages_3` add INDEX `user_messages3_mid_index` ( `_mid` );\nalter table `t_user_messages_4` add INDEX `user_messages4_mid_index` ( `_mid` );\nalter table `t_user_messages_5` add INDEX `user_messages5_mid_index` ( `_mid` );\nalter table `t_user_messages_6` add INDEX `user_messages6_mid_index` ( `_mid` );\nalter table `t_user_messages_7` add INDEX `user_messages7_mid_index` ( `_mid` );\nalter table `t_user_messages_8` add INDEX `user_messages8_mid_index` ( `_mid` );\nalter table `t_user_messages_9` add INDEX `user_messages9_mid_index` ( `_mid` );\nalter table `t_user_messages_10` add INDEX `user_messages10_mid_index` ( `_mid` );\nalter table `t_user_messages_11` add INDEX `user_messages11_mid_index` ( `_mid` );\nalter table `t_user_messages_12` add INDEX `user_messages12_mid_index` ( `_mid` );\nalter table `t_user_messages_13` add INDEX `user_messages13_mid_index` ( `_mid` );\nalter table `t_user_messages_14` add INDEX `user_messages14_mid_index` ( `_mid` );\nalter table `t_user_messages_15` add INDEX `user_messages15_mid_index` ( `_mid` );\nalter table `t_user_messages_16` add INDEX `user_messages16_mid_index` ( `_mid` );\nalter table `t_user_messages_17` add INDEX `user_messages17_mid_index` ( `_mid` );\nalter table `t_user_messages_18` add INDEX `user_messages18_mid_index` ( `_mid` );\nalter table `t_user_messages_19` add INDEX `user_messages19_mid_index` ( `_mid` );\nalter table `t_user_messages_20` add INDEX `user_messages20_mid_index` ( `_mid` );\nalter table `t_user_messages_21` add INDEX `user_messages21_mid_index` ( `_mid` );\nalter table `t_user_messages_22` add INDEX `user_messages22_mid_index` ( `_mid` );\nalter table `t_user_messages_23` add INDEX `user_messages23_mid_index` ( `_mid` );\nalter table `t_user_messages_24` add INDEX `user_messages24_mid_index` ( `_mid` );\nalter table `t_user_messages_25` add INDEX `user_messages25_mid_index` ( `_mid` );\nalter table `t_user_messages_26` add INDEX `user_messages26_mid_index` ( `_mid` );\nalter table `t_user_messages_27` add INDEX `user_messages27_mid_index` ( `_mid` );\nalter table `t_user_messages_28` add INDEX `user_messages28_mid_index` ( `_mid` );\nalter table `t_user_messages_29` add INDEX `user_messages29_mid_index` ( `_mid` );\nalter table `t_user_messages_30` add INDEX `user_messages30_mid_index` ( `_mid` );\nalter table `t_user_messages_31` add INDEX `user_messages31_mid_index` ( `_mid` );\nalter table `t_user_messages_32` add INDEX `user_messages32_mid_index` ( `_mid` );\nalter table `t_user_messages_33` add INDEX `user_messages33_mid_index` ( `_mid` );\nalter table `t_user_messages_34` add INDEX `user_messages34_mid_index` ( `_mid` );\nalter table `t_user_messages_35` add INDEX `user_messages35_mid_index` ( `_mid` );\nalter table `t_user_messages_36` add INDEX `user_messages36_mid_index` ( `_mid` );\nalter table `t_user_messages_37` add INDEX `user_messages37_mid_index` ( `_mid` );\nalter table `t_user_messages_38` add INDEX `user_messages38_mid_index` ( `_mid` );\nalter table `t_user_messages_39` add INDEX `user_messages39_mid_index` ( `_mid` );\nalter table `t_user_messages_40` add INDEX `user_messages40_mid_index` ( `_mid` );\nalter table `t_user_messages_41` add INDEX `user_messages41_mid_index` ( `_mid` );\nalter table `t_user_messages_42` add INDEX `user_messages42_mid_index` ( `_mid` );\nalter table `t_user_messages_43` add INDEX `user_messages43_mid_index` ( `_mid` );\nalter table `t_user_messages_44` add INDEX `user_messages44_mid_index` ( `_mid` );\nalter table `t_user_messages_45` add INDEX `user_messages45_mid_index` ( `_mid` );\nalter table `t_user_messages_46` add INDEX `user_messages46_mid_index` ( `_mid` );\nalter table `t_user_messages_47` add INDEX `user_messages47_mid_index` ( `_mid` );\nalter table `t_user_messages_48` add INDEX `user_messages48_mid_index` ( `_mid` );\nalter table `t_user_messages_49` add INDEX `user_messages49_mid_index` ( `_mid` );\nalter table `t_user_messages_50` add INDEX `user_messages50_mid_index` ( `_mid` );\nalter table `t_user_messages_51` add INDEX `user_messages51_mid_index` ( `_mid` );\nalter table `t_user_messages_52` add INDEX `user_messages52_mid_index` ( `_mid` );\nalter table `t_user_messages_53` add INDEX `user_messages53_mid_index` ( `_mid` );\nalter table `t_user_messages_54` add INDEX `user_messages54_mid_index` ( `_mid` );\nalter table `t_user_messages_55` add INDEX `user_messages55_mid_index` ( `_mid` );\nalter table `t_user_messages_56` add INDEX `user_messages56_mid_index` ( `_mid` );\nalter table `t_user_messages_57` add INDEX `user_messages57_mid_index` ( `_mid` );\nalter table `t_user_messages_58` add INDEX `user_messages58_mid_index` ( `_mid` );\nalter table `t_user_messages_59` add INDEX `user_messages59_mid_index` ( `_mid` );\nalter table `t_user_messages_60` add INDEX `user_messages60_mid_index` ( `_mid` );\nalter table `t_user_messages_61` add INDEX `user_messages61_mid_index` ( `_mid` );\nalter table `t_user_messages_62` add INDEX `user_messages62_mid_index` ( `_mid` );\nalter table `t_user_messages_63` add INDEX `user_messages63_mid_index` ( `_mid` );\nalter table `t_user_messages_64` add INDEX `user_messages64_mid_index` ( `_mid` );\nalter table `t_user_messages_65` add INDEX `user_messages65_mid_index` ( `_mid` );\nalter table `t_user_messages_66` add INDEX `user_messages66_mid_index` ( `_mid` );\nalter table `t_user_messages_67` add INDEX `user_messages67_mid_index` ( `_mid` );\nalter table `t_user_messages_68` add INDEX `user_messages68_mid_index` ( `_mid` );\nalter table `t_user_messages_69` add INDEX `user_messages69_mid_index` ( `_mid` );\nalter table `t_user_messages_70` add INDEX `user_messages70_mid_index` ( `_mid` );\nalter table `t_user_messages_71` add INDEX `user_messages71_mid_index` ( `_mid` );\nalter table `t_user_messages_72` add INDEX `user_messages72_mid_index` ( `_mid` );\nalter table `t_user_messages_73` add INDEX `user_messages73_mid_index` ( `_mid` );\nalter table `t_user_messages_74` add INDEX `user_messages74_mid_index` ( `_mid` );\nalter table `t_user_messages_75` add INDEX `user_messages75_mid_index` ( `_mid` );\nalter table `t_user_messages_76` add INDEX `user_messages76_mid_index` ( `_mid` );\nalter table `t_user_messages_77` add INDEX `user_messages77_mid_index` ( `_mid` );\nalter table `t_user_messages_78` add INDEX `user_messages78_mid_index` ( `_mid` );\nalter table `t_user_messages_79` add INDEX `user_messages79_mid_index` ( `_mid` );\nalter table `t_user_messages_80` add INDEX `user_messages80_mid_index` ( `_mid` );\nalter table `t_user_messages_81` add INDEX `user_messages81_mid_index` ( `_mid` );\nalter table `t_user_messages_82` add INDEX `user_messages82_mid_index` ( `_mid` );\nalter table `t_user_messages_83` add INDEX `user_messages83_mid_index` ( `_mid` );\nalter table `t_user_messages_84` add INDEX `user_messages84_mid_index` ( `_mid` );\nalter table `t_user_messages_85` add INDEX `user_messages85_mid_index` ( `_mid` );\nalter table `t_user_messages_86` add INDEX `user_messages86_mid_index` ( `_mid` );\nalter table `t_user_messages_87` add INDEX `user_messages87_mid_index` ( `_mid` );\nalter table `t_user_messages_88` add INDEX `user_messages88_mid_index` ( `_mid` );\nalter table `t_user_messages_89` add INDEX `user_messages89_mid_index` ( `_mid` );\nalter table `t_user_messages_90` add INDEX `user_messages90_mid_index` ( `_mid` );\nalter table `t_user_messages_91` add INDEX `user_messages91_mid_index` ( `_mid` );\nalter table `t_user_messages_92` add INDEX `user_messages92_mid_index` ( `_mid` );\nalter table `t_user_messages_93` add INDEX `user_messages93_mid_index` ( `_mid` );\nalter table `t_user_messages_94` add INDEX `user_messages94_mid_index` ( `_mid` );\nalter table `t_user_messages_95` add INDEX `user_messages95_mid_index` ( `_mid` );\nalter table `t_user_messages_96` add INDEX `user_messages96_mid_index` ( `_mid` );\nalter table `t_user_messages_97` add INDEX `user_messages97_mid_index` ( `_mid` );\nalter table `t_user_messages_98` add INDEX `user_messages98_mid_index` ( `_mid` );\nalter table `t_user_messages_99` add INDEX `user_messages99_mid_index` ( `_mid` );\nalter table `t_user_messages_100` add INDEX `user_messages100_mid_index` ( `_mid` );\nalter table `t_user_messages_101` add INDEX `user_messages101_mid_index` ( `_mid` );\nalter table `t_user_messages_102` add INDEX `user_messages102_mid_index` ( `_mid` );\nalter table `t_user_messages_103` add INDEX `user_messages103_mid_index` ( `_mid` );\nalter table `t_user_messages_104` add INDEX `user_messages104_mid_index` ( `_mid` );\nalter table `t_user_messages_105` add INDEX `user_messages105_mid_index` ( `_mid` );\nalter table `t_user_messages_106` add INDEX `user_messages106_mid_index` ( `_mid` );\nalter table `t_user_messages_107` add INDEX `user_messages107_mid_index` ( `_mid` );\nalter table `t_user_messages_108` add INDEX `user_messages108_mid_index` ( `_mid` );\nalter table `t_user_messages_109` add INDEX `user_messages109_mid_index` ( `_mid` );\nalter table `t_user_messages_110` add INDEX `user_messages110_mid_index` ( `_mid` );\nalter table `t_user_messages_111` add INDEX `user_messages111_mid_index` ( `_mid` );\nalter table `t_user_messages_112` add INDEX `user_messages112_mid_index` ( `_mid` );\nalter table `t_user_messages_113` add INDEX `user_messages113_mid_index` ( `_mid` );\nalter table `t_user_messages_114` add INDEX `user_messages114_mid_index` ( `_mid` );\nalter table `t_user_messages_115` add INDEX `user_messages115_mid_index` ( `_mid` );\nalter table `t_user_messages_116` add INDEX `user_messages116_mid_index` ( `_mid` );\nalter table `t_user_messages_117` add INDEX `user_messages117_mid_index` ( `_mid` );\nalter table `t_user_messages_118` add INDEX `user_messages118_mid_index` ( `_mid` );\nalter table `t_user_messages_119` add INDEX `user_messages119_mid_index` ( `_mid` );\nalter table `t_user_messages_120` add INDEX `user_messages120_mid_index` ( `_mid` );\nalter table `t_user_messages_121` add INDEX `user_messages121_mid_index` ( `_mid` );\nalter table `t_user_messages_122` add INDEX `user_messages122_mid_index` ( `_mid` );\nalter table `t_user_messages_123` add INDEX `user_messages123_mid_index` ( `_mid` );\nalter table `t_user_messages_124` add INDEX `user_messages124_mid_index` ( `_mid` );\nalter table `t_user_messages_125` add INDEX `user_messages125_mid_index` ( `_mid` );\nalter table `t_user_messages_126` add INDEX `user_messages126_mid_index` ( `_mid` );\nalter table `t_user_messages_127` add INDEX `user_messages127_mid_index` ( `_mid` );\n"
  },
  {
    "path": "broker/migrate/mysql/V43__add_user_messages_conv_info.sql",
    "content": "alter table `t_user_messages` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_0` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_0` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_0` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_0` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_1` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_1` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_1` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_1` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_2` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_2` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_2` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_2` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_3` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_3` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_3` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_3` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_4` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_4` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_4` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_4` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_5` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_5` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_5` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_5` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_6` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_6` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_6` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_6` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_7` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_7` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_7` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_7` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_8` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_8` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_8` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_8` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_9` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_9` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_9` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_9` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_10` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_10` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_10` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_10` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_11` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_11` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_11` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_11` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_12` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_12` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_12` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_12` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_13` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_13` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_13` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_13` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_14` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_14` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_14` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_14` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_15` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_15` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_15` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_15` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_16` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_16` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_16` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_16` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_17` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_17` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_17` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_17` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_18` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_18` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_18` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_18` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_19` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_19` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_19` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_19` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_20` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_20` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_20` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_20` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_21` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_21` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_21` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_21` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_22` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_22` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_22` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_22` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_23` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_23` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_23` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_23` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_24` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_24` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_24` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_24` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_25` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_25` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_25` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_25` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_26` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_26` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_26` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_26` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_27` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_27` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_27` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_27` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_28` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_28` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_28` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_28` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_29` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_29` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_29` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_29` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_30` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_30` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_30` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_30` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_31` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_31` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_31` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_31` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_32` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_32` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_32` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_32` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_33` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_33` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_33` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_33` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_34` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_34` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_34` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_34` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_35` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_35` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_35` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_35` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_36` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_36` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_36` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_36` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_37` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_37` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_37` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_37` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_38` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_38` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_38` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_38` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_39` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_39` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_39` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_39` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_40` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_40` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_40` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_40` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_41` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_41` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_41` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_41` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_42` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_42` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_42` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_42` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_43` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_43` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_43` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_43` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_44` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_44` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_44` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_44` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_45` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_45` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_45` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_45` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_46` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_46` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_46` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_46` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_47` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_47` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_47` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_47` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_48` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_48` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_48` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_48` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_49` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_49` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_49` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_49` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_50` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_50` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_50` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_50` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_51` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_51` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_51` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_51` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_52` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_52` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_52` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_52` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_53` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_53` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_53` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_53` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_54` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_54` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_54` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_54` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_55` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_55` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_55` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_55` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_56` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_56` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_56` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_56` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_57` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_57` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_57` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_57` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_58` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_58` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_58` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_58` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_59` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_59` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_59` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_59` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_60` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_60` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_60` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_60` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_61` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_61` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_61` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_61` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_62` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_62` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_62` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_62` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_63` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_63` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_63` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_63` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_64` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_64` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_64` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_64` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_65` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_65` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_65` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_65` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_66` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_66` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_66` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_66` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_67` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_67` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_67` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_67` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_68` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_68` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_68` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_68` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_69` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_69` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_69` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_69` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_70` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_70` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_70` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_70` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_71` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_71` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_71` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_71` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_72` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_72` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_72` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_72` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_73` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_73` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_73` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_73` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_74` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_74` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_74` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_74` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_75` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_75` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_75` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_75` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_76` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_76` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_76` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_76` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_77` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_77` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_77` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_77` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_78` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_78` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_78` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_78` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_79` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_79` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_79` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_79` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_80` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_80` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_80` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_80` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_81` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_81` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_81` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_81` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_82` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_82` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_82` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_82` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_83` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_83` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_83` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_83` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_84` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_84` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_84` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_84` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_85` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_85` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_85` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_85` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_86` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_86` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_86` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_86` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_87` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_87` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_87` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_87` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_88` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_88` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_88` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_88` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_89` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_89` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_89` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_89` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_90` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_90` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_90` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_90` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_91` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_91` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_91` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_91` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_92` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_92` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_92` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_92` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_93` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_93` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_93` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_93` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_94` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_94` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_94` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_94` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_95` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_95` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_95` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_95` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_96` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_96` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_96` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_96` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_97` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_97` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_97` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_97` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_98` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_98` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_98` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_98` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_99` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_99` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_99` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_99` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_100` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_100` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_100` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_100` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_101` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_101` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_101` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_101` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_102` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_102` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_102` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_102` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_103` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_103` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_103` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_103` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_104` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_104` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_104` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_104` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_105` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_105` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_105` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_105` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_106` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_106` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_106` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_106` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_107` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_107` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_107` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_107` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_108` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_108` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_108` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_108` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_109` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_109` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_109` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_109` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_110` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_110` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_110` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_110` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_111` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_111` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_111` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_111` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_112` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_112` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_112` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_112` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_113` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_113` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_113` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_113` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_114` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_114` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_114` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_114` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_115` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_115` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_115` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_115` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_116` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_116` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_116` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_116` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_117` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_117` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_117` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_117` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_118` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_118` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_118` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_118` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_119` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_119` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_119` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_119` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_120` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_120` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_120` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_120` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_121` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_121` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_121` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_121` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_122` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_122` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_122` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_122` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_123` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_123` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_123` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_123` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_124` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_124` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_124` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_124` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_125` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_125` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_125` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_125` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_126` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_126` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_126` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_126` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n\nalter table `t_user_messages_127` add column `_type` tinyint(4) NOT NULL DEFAULT '0';\nalter table `t_user_messages_127` add column `_target` varchar(129) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';\nalter table `t_user_messages_127` add column `_directing` tinyint(1) NOT NULL DEFAULT '0';\nalter table `t_user_messages_127` add INDEX `user_messages_conv_index` ( `_uid`, `_type`, `_target`, `_line`, `_mid` desc);\n"
  },
  {
    "path": "broker/migrate/mysql/V44__add_group_member_friend_request_extra.sql",
    "content": "alter table `t_group_member` add column `_extra` TEXT DEFAULT NULL;\nalter table `t_friend_request` add column `_extra` TEXT DEFAULT NULL;\n"
  },
  {
    "path": "broker/migrate/mysql/V45__add_user_messages_cont_type.sql",
    "content": "alter table `t_user_messages` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_0` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_1` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_2` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_3` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_4` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_5` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_6` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_7` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_8` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_9` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_10` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_11` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_12` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_13` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_14` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_15` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_16` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_17` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_18` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_19` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_20` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_21` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_22` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_23` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_24` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_25` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_26` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_27` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_28` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_29` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_30` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_31` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_32` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_33` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_34` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_35` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_36` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_37` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_38` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_39` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_40` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_41` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_42` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_43` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_44` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_45` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_46` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_47` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_48` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_49` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_50` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_51` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_52` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_53` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_54` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_55` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_56` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_57` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_58` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_59` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_60` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_61` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_62` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_63` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_64` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_65` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_66` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_67` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_68` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_69` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_70` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_71` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_72` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_73` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_74` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_75` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_76` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_77` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_78` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_79` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_80` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_81` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_82` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_83` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_84` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_85` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_86` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_87` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_88` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_89` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_90` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_91` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_92` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_93` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_94` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_95` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_96` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_97` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_98` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_99` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_100` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_101` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_102` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_103` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_104` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_105` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_106` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_107` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_108` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_109` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_110` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_111` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_112` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_113` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_114` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_115` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_116` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_117` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_118` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_119` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_120` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_121` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_122` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_123` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_124` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_125` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_126` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n\nalter table `t_user_messages_127` add column `_cont_type` int(11) NOT NULL DEFAULT '0';\n"
  },
  {
    "path": "broker/migrate/mysql/V46__utf8mb4_unicode_ci_to_utf8mb4_bin.sql",
    "content": "ALTER TABLE `t_channel` MODIFY COLUMN `_cid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_channel` MODIFY COLUMN `_owner` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_channel_listener` MODIFY COLUMN `_cid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_channel_listener` MODIFY COLUMN `_mid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_chatroom` MODIFY COLUMN `_cid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_chatroom_blacklist` MODIFY COLUMN `_cid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_chatroom_blacklist` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_chatroom_manager` MODIFY COLUMN `_cid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_chatroom_manager` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_delivery_report` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_device` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_file` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_file` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_friend` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_friend` MODIFY COLUMN `_friend_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_friend_request` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_friend_request` MODIFY COLUMN `_friend_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_group` MODIFY COLUMN `_gid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_group` MODIFY COLUMN `_owner` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT '';\n\nALTER TABLE `t_group_member` MODIFY COLUMN `_gid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_group_member` MODIFY COLUMN `_mid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\n\nALTER TABLE `t_messages` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_0` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_0` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_0` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_1` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_1` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_1` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_10` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_10` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_10` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_11` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_11` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_11` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_12` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_12` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_12` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_13` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_13` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_13` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_14` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_14` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_14` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_15` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_15` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_15` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_16` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_16` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_16` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_17` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_17` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_17` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_18` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_18` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_18` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_19` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_19` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_19` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_2` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_2` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_2` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_20` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_20` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_20` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_21` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_21` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_21` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_22` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_22` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_22` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_23` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_23` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_23` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_24` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_24` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_24` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_25` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_25` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_25` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_26` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_26` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_26` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_27` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_27` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_27` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_28` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_28` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_28` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_29` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_29` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_29` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_3` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_3` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_3` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_30` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_30` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_30` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_31` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_31` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_31` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_32` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_32` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_32` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_33` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_33` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_33` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_34` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_34` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_34` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_35` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_35` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_35` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_4` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_4` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_4` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_5` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_5` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_5` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_6` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_6` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_6` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_7` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_7` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_7` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_8` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_8` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_8` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_messages_9` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_9` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_messages_9` MODIFY COLUMN `_to` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_read_report` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_read_report` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_robot` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_robot` MODIFY COLUMN `_owner` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT '';\n\nALTER TABLE `t_sensitive_messages` MODIFY COLUMN `_from` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_sensitive_messages` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_session` MODIFY COLUMN `row_id` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user` MODIFY COLUMN `_name` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_delivery_report` MODIFY COLUMN `_rid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_delivery_report` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_device` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_device` MODIFY COLUMN `_did` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_0` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_0` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_1` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_1` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_10` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_10` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_100` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_100` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_101` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_101` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_102` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_102` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_103` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_103` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_104` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_104` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_105` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_105` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_106` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_106` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_107` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_107` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_108` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_108` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_109` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_109` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_11` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_11` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_110` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_110` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_111` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_111` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_112` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_112` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_113` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_113` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_114` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_114` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_115` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_115` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_116` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_116` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_117` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_117` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_118` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_118` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_119` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_119` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_12` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_12` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_120` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_120` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_121` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_121` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_122` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_122` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_123` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_123` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_124` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_124` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_125` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_125` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_126` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_126` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_127` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_127` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_13` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_13` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_14` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_14` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_15` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_15` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_16` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_16` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_17` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_17` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_18` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_18` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_19` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_19` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_2` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_2` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_20` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_20` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_21` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_21` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_22` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_22` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_23` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_23` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_24` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_24` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_25` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_25` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_26` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_26` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_27` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_27` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_28` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_28` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_29` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_29` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_3` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_3` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_30` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_30` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_31` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_31` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_32` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_32` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_33` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_33` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_34` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_34` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_35` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_35` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_36` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_36` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_37` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_37` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_38` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_38` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_39` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_39` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_4` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_4` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_40` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_40` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_41` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_41` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_42` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_42` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_43` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_43` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_44` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_44` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_45` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_45` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_46` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_46` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_47` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_47` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_48` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_48` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_49` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_49` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_5` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_5` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_50` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_50` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_51` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_51` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_52` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_52` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_53` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_53` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_54` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_54` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_55` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_55` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_56` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_56` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_57` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_57` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_58` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_58` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_59` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_59` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_6` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_6` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_60` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_60` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_61` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_61` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_62` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_62` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_63` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_63` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_64` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_64` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_65` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_65` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_66` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_66` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_67` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_67` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_68` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_68` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_69` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_69` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_7` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_7` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_70` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_70` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_71` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_71` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_72` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_72` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_73` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_73` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_74` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_74` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_75` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_75` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_76` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_76` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_77` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_77` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_78` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_78` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_79` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_79` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_8` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_8` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_80` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_80` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_81` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_81` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_82` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_82` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_83` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_83` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_84` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_84` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_85` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_85` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_86` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_86` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_87` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_87` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_88` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_88` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_89` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_89` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_9` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_9` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_90` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_90` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_91` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_91` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_92` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_92` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_93` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_93` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_94` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_94` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_95` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_95` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_96` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_96` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_97` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_97` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_98` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_98` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_messages_99` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_messages_99` MODIFY COLUMN `_target` VARCHAR(129) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_read_report` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_session` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_session` MODIFY COLUMN `_cid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_session` MODIFY COLUMN `_token` VARCHAR(240) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n\nALTER TABLE `t_user_setting` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\nALTER TABLE `t_user_setting` MODIFY COLUMN `_key` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n\nALTER TABLE `t_user_status` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n"
  },
  {
    "path": "broker/migrate/mysql/V47__fix_read_report_error.sql",
    "content": "\nALTER TABLE `t_read_report` MODIFY COLUMN `_uid` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\nALTER TABLE `t_read_report` MODIFY COLUMN `_target` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL;\n"
  },
  {
    "path": "broker/migrate/mysql/V48__alter_user_setting_key_column.sql",
    "content": "alter table `t_user_setting` modify column `_key` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;\n"
  },
  {
    "path": "broker/migrate/mysql/V49__create_secret_chat_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_secret_chat`;\nCREATE TABLE `t_secret_chat` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_from` varchar(64) DEFAULT '',\n  `_from_cid` varchar(64) DEFAULT '',\n  `_to` varchar(64) DEFAULT '',\n  `_to_cid` varchar(64) DEFAULT '',\n  `_state` tinyint NOT NULL DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  UNIQUE INDEX `secret_chat_uid_index` (`_uid` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n"
  },
  {
    "path": "broker/migrate/mysql/V4__create_default_chatroom.sql",
    "content": "insert into t_chatroom (`_cid`, `_title`, `_desc`,`_dt`) values ('chatroom1','火信聊天室1','火信测试聊天室1，用来演示聊天室功能', 1);\n\ninsert into t_chatroom (`_cid`, `_title`, `_desc`,`_dt`) values ('chatroom2','火信聊天室2','火信测试聊天室2，用来演示聊天室功能', 1);\n\ninsert into t_chatroom (`_cid`, `_title`, `_desc`,`_dt`) values ('chatroom3','火信聊天室3','火信测试聊天室3，用来演示聊天室功能', 1);\n"
  },
  {
    "path": "broker/migrate/mysql/V50__add_message_table_conversation_index.sql",
    "content": "alter table `t_messages` add INDEX `messages_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_0` add INDEX `messages0_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_1` add INDEX `messages1_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_2` add INDEX `messages2_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_3` add INDEX `messages3_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_4` add INDEX `messages4_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_5` add INDEX `messages5_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_6` add INDEX `messages6_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_7` add INDEX `messages7_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_8` add INDEX `messages8_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_9` add INDEX `messages9_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_10` add INDEX `messages10_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_11` add INDEX `messages11_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_12` add INDEX `messages12_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_13` add INDEX `messages13_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_14` add INDEX `messages14_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_15` add INDEX `messages15_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_16` add INDEX `messages16_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_17` add INDEX `messages17_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_18` add INDEX `messages18_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_19` add INDEX `messages19_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_20` add INDEX `messages20_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_21` add INDEX `messages21_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_22` add INDEX `messages22_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_23` add INDEX `messages23_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_24` add INDEX `messages24_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_25` add INDEX `messages25_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_26` add INDEX `messages26_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_27` add INDEX `messages27_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_28` add INDEX `messages28_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_29` add INDEX `messages29_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_30` add INDEX `messages30_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_31` add INDEX `messages31_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_32` add INDEX `messages32_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_33` add INDEX `messages33_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_34` add INDEX `messages34_conv_index` (`_type`, `_target`, `_line`);\nalter table `t_messages_35` add INDEX `messages35_conv_index` (`_type`, `_target`, `_line`);\n"
  },
  {
    "path": "broker/migrate/mysql/V51__add_channel_listener_table_member_index.sql",
    "content": "alter table `t_channel_listener` add INDEX `channel_mid_index` (`_mid`);\n"
  },
  {
    "path": "broker/migrate/mysql/V52__add_channel_menu_column.sql",
    "content": "alter table `t_channel` add column `_menu` BLOB DEFAULT NULL;\n"
  },
  {
    "path": "broker/migrate/mysql/V53__add_group_member_mid_index.sql",
    "content": "alter table `t_group_member` add INDEX `group_member_mid_index` (`_mid`);\n"
  },
  {
    "path": "broker/migrate/mysql/V54__create_super_group.sql",
    "content": "alter table `t_group` add column `_super_group` tinyint NOT NULL DEFAULT 0;\n\nDROP TABLE IF EXISTS `t_group_messages`;\nCREATE TABLE `t_group_messages` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_0`;\nCREATE TABLE `t_group_messages_0` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message0_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_1`;\nCREATE TABLE `t_group_messages_1` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message1_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_2`;\nCREATE TABLE `t_group_messages_2` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message2_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_3`;\nCREATE TABLE `t_group_messages_3` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message3_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_4`;\nCREATE TABLE `t_group_messages_4` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message4_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_5`;\nCREATE TABLE `t_group_messages_5` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message5_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_6`;\nCREATE TABLE `t_group_messages_6` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message6_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_7`;\nCREATE TABLE `t_group_messages_7` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message7_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_8`;\nCREATE TABLE `t_group_messages_8` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message8_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_9`;\nCREATE TABLE `t_group_messages_9` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message9_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_10`;\nCREATE TABLE `t_group_messages_10` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message10_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_11`;\nCREATE TABLE `t_group_messages_11` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message11_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_12`;\nCREATE TABLE `t_group_messages_12` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message12_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_13`;\nCREATE TABLE `t_group_messages_13` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message13_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_14`;\nCREATE TABLE `t_group_messages_14` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message14_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_15`;\nCREATE TABLE `t_group_messages_15` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message15_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_16`;\nCREATE TABLE `t_group_messages_16` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message16_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_17`;\nCREATE TABLE `t_group_messages_17` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message17_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_18`;\nCREATE TABLE `t_group_messages_18` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message18_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_19`;\nCREATE TABLE `t_group_messages_19` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message19_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\n\n\nDROP TABLE IF EXISTS `t_group_messages_20`;\nCREATE TABLE `t_group_messages_20` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message20_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_21`;\nCREATE TABLE `t_group_messages_21` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message21_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_22`;\nCREATE TABLE `t_group_messages_22` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message22_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_23`;\nCREATE TABLE `t_group_messages_23` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message23_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_24`;\nCREATE TABLE `t_group_messages_24` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message24_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_25`;\nCREATE TABLE `t_group_messages_25` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message25_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_26`;\nCREATE TABLE `t_group_messages_26` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message26_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_27`;\nCREATE TABLE `t_group_messages_27` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message27_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_28`;\nCREATE TABLE `t_group_messages_28` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message28_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_29`;\nCREATE TABLE `t_group_messages_29` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message29_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\n\nDROP TABLE IF EXISTS `t_group_messages_30`;\nCREATE TABLE `t_group_messages_30` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message30_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_31`;\nCREATE TABLE `t_group_messages_31` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message31_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_32`;\nCREATE TABLE `t_group_messages_32` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message32_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_33`;\nCREATE TABLE `t_group_messages_33` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message33_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_34`;\nCREATE TABLE `t_group_messages_34` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message34_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_35`;\nCREATE TABLE `t_group_messages_35` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message35_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_36`;\nCREATE TABLE `t_group_messages_36` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message36_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_37`;\nCREATE TABLE `t_group_messages_37` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message37_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_38`;\nCREATE TABLE `t_group_messages_38` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message38_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_39`;\nCREATE TABLE `t_group_messages_39` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message39_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\n\nDROP TABLE IF EXISTS `t_group_messages_40`;\nCREATE TABLE `t_group_messages_40` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message40_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_41`;\nCREATE TABLE `t_group_messages_41` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message41_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_42`;\nCREATE TABLE `t_group_messages_42` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message42_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_43`;\nCREATE TABLE `t_group_messages_43` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message43_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_44`;\nCREATE TABLE `t_group_messages_44` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message44_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_45`;\nCREATE TABLE `t_group_messages_45` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message45_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_46`;\nCREATE TABLE `t_group_messages_46` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message46_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_47`;\nCREATE TABLE `t_group_messages_47` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message47_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_48`;\nCREATE TABLE `t_group_messages_48` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message48_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_49`;\nCREATE TABLE `t_group_messages_49` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message49_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\n\nDROP TABLE IF EXISTS `t_group_messages_50`;\nCREATE TABLE `t_group_messages_50` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message50_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_51`;\nCREATE TABLE `t_group_messages_51` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message51_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_52`;\nCREATE TABLE `t_group_messages_52` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message52_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_53`;\nCREATE TABLE `t_group_messages_53` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message53_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_54`;\nCREATE TABLE `t_group_messages_54` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message54_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_55`;\nCREATE TABLE `t_group_messages_55` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message55_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_56`;\nCREATE TABLE `t_group_messages_56` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message56_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_57`;\nCREATE TABLE `t_group_messages_57` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message57_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_58`;\nCREATE TABLE `t_group_messages_58` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message58_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_59`;\nCREATE TABLE `t_group_messages_59` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message59_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\n\nDROP TABLE IF EXISTS `t_group_messages_60`;\nCREATE TABLE `t_group_messages_60` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message60_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_61`;\nCREATE TABLE `t_group_messages_61` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message61_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_62`;\nCREATE TABLE `t_group_messages_62` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message62_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_63`;\nCREATE TABLE `t_group_messages_63` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message63_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_64`;\nCREATE TABLE `t_group_messages_64` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message64_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_65`;\nCREATE TABLE `t_group_messages_65` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message65_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_66`;\nCREATE TABLE `t_group_messages_66` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message66_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_67`;\nCREATE TABLE `t_group_messages_67` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message67_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_68`;\nCREATE TABLE `t_group_messages_68` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message68_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_69`;\nCREATE TABLE `t_group_messages_69` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message69_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\n\nDROP TABLE IF EXISTS `t_group_messages_70`;\nCREATE TABLE `t_group_messages_70` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message70_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_71`;\nCREATE TABLE `t_group_messages_71` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message71_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_72`;\nCREATE TABLE `t_group_messages_72` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message72_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_73`;\nCREATE TABLE `t_group_messages_73` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message73_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_74`;\nCREATE TABLE `t_group_messages_74` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message74_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_75`;\nCREATE TABLE `t_group_messages_75` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message75_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_76`;\nCREATE TABLE `t_group_messages_76` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message76_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_77`;\nCREATE TABLE `t_group_messages_77` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message77_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_78`;\nCREATE TABLE `t_group_messages_78` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message78_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_79`;\nCREATE TABLE `t_group_messages_79` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message79_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\n\nDROP TABLE IF EXISTS `t_group_messages_80`;\nCREATE TABLE `t_group_messages_80` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message80_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_81`;\nCREATE TABLE `t_group_messages_81` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message81_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_82`;\nCREATE TABLE `t_group_messages_82` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message82_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_83`;\nCREATE TABLE `t_group_messages_83` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message83_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_84`;\nCREATE TABLE `t_group_messages_84` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message84_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_85`;\nCREATE TABLE `t_group_messages_85` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message85_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_86`;\nCREATE TABLE `t_group_messages_86` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message86_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_87`;\nCREATE TABLE `t_group_messages_87` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message87_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_88`;\nCREATE TABLE `t_group_messages_88` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message88_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_89`;\nCREATE TABLE `t_group_messages_89` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message89_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\n\nDROP TABLE IF EXISTS `t_group_messages_90`;\nCREATE TABLE `t_group_messages_90` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message90_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_91`;\nCREATE TABLE `t_group_messages_91` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message91_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_92`;\nCREATE TABLE `t_group_messages_92` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message92_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_93`;\nCREATE TABLE `t_group_messages_93` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message93_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_94`;\nCREATE TABLE `t_group_messages_94` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message94_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_95`;\nCREATE TABLE `t_group_messages_95` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message95_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_96`;\nCREATE TABLE `t_group_messages_96` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message96_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_97`;\nCREATE TABLE `t_group_messages_97` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message97_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_98`;\nCREATE TABLE `t_group_messages_98` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message98_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_99`;\nCREATE TABLE `t_group_messages_99` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message99_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\n\nDROP TABLE IF EXISTS `t_group_messages_100`;\nCREATE TABLE `t_group_messages_100` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message100_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_101`;\nCREATE TABLE `t_group_messages_101` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message101_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_102`;\nCREATE TABLE `t_group_messages_102` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message102_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_103`;\nCREATE TABLE `t_group_messages_103` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message103_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_104`;\nCREATE TABLE `t_group_messages_104` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message104_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_105`;\nCREATE TABLE `t_group_messages_105` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message105_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_106`;\nCREATE TABLE `t_group_messages_106` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message106_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_107`;\nCREATE TABLE `t_group_messages_107` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message107_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_108`;\nCREATE TABLE `t_group_messages_108` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message108_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_109`;\nCREATE TABLE `t_group_messages_109` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message109_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\n\nDROP TABLE IF EXISTS `t_group_messages_110`;\nCREATE TABLE `t_group_messages_110` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message110_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_111`;\nCREATE TABLE `t_group_messages_111` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message111_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_112`;\nCREATE TABLE `t_group_messages_112` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message112_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_113`;\nCREATE TABLE `t_group_messages_113` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message113_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_114`;\nCREATE TABLE `t_group_messages_114` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message114_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_115`;\nCREATE TABLE `t_group_messages_115` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message115_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_116`;\nCREATE TABLE `t_group_messages_116` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message116_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_117`;\nCREATE TABLE `t_group_messages_117` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message117_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_118`;\nCREATE TABLE `t_group_messages_118` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message118_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_119`;\nCREATE TABLE `t_group_messages_119` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message119_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\n\nDROP TABLE IF EXISTS `t_group_messages_120`;\nCREATE TABLE `t_group_messages_120` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message120_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_121`;\nCREATE TABLE `t_group_messages_121` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message121_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_122`;\nCREATE TABLE `t_group_messages_122` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message122_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_123`;\nCREATE TABLE `t_group_messages_123` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message123_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_124`;\nCREATE TABLE `t_group_messages_124` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message124_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_125`;\nCREATE TABLE `t_group_messages_125` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message125_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_126`;\nCREATE TABLE `t_group_messages_126` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message126_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n\nDROP TABLE IF EXISTS `t_group_messages_127`;\nCREATE TABLE `t_group_messages_127` (\n    `_mid` bigint(20) NOT NULL PRIMARY KEY,\n    `_sender` varchar(64) NOT NULL,\n    `_gid` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL,\n    `_client_id` varchar(64) NULL,\n    `_seq` bigint(20) NOT NULL,\n    `_persist_flag` int(11) NOT NULL,\n    `_mentioned_type` int(11) NOT NULL,\n    `_mentioned_targets` BLOB NULL,\n    `_to` BLOB NULL,\n    `_cont_type` int(11) NOT NULL DEFAULT 0,\n    `_duration` int(11) NOT NULL DEFAULT 0,\n    `_dt` bigint(20) NOT NULL DEFAULT 0,\n    INDEX `group_message127_seq_uid_index` (`_gid` DESC, `_line`, `_seq` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_bin;\n"
  },
  {
    "path": "broker/migrate/mysql/V55__group_add_deleted_column.sql",
    "content": "alter table `t_group` add column `_deleted` tinyint NOT NULL DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/mysql/V56__add_domain_table.sql",
    "content": "DROP TABLE IF EXISTS `t_domain`;\nCREATE TABLE `t_domain` (\n  `_domain_id` varchar(128) NOT NULL PRIMARY KEY,\n  `_name` varchar(64) NOT NULL,\n  `_desc` varchar(256) DEFAULT '',\n  `_email` varchar(64) DEFAULT '',\n  `_tel` varchar(64) DEFAULT '',\n  `_address` varchar(64) DEFAULT '',\n  `_extra` varchar(1024) DEFAULT '',\n  `_dt` bigint(20) NOT NULL\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\nalter table `t_user` add column `_external` tinyint DEFAULT 0;\n"
  },
  {
    "path": "broker/migrate/mysql/V57__update_group_member_index.sql",
    "content": "CREATE INDEX `user_gid_mid_dt_index` ON `t_group_member` (`_gid`, `_mid`, `_dt`);\n"
  },
  {
    "path": "broker/migrate/mysql/V58__reupdate_group_member_index.sql",
    "content": "DROP INDEX `user_gid_mid_dt_index` ON `t_group_member`;\nCREATE INDEX `user_gid_dt_index` ON `t_group_member` (`_gid`, `_dt`);\n"
  },
  {
    "path": "broker/migrate/mysql/V59__add_no_allow_name_setting.sql",
    "content": "insert into t_settings(`id`, `_value`,`_desc`) values (2, '文件传输助手,客服,官方', '禁止使用名称，如果有多个，以英文逗号隔开。直接修改数据库，不用重启IM服务');\n"
  },
  {
    "path": "broker/migrate/mysql/V5__create_default_robot.sql",
    "content": "insert into t_user (`_uid`,`_name`,`_display_name`,`_portrait`,`_type`,`_dt`) values ('FireRobot','FireRobot','小火','http://cdn2.wildfirechat.cn/robot.png',1,1);\n\ninsert into t_robot (`_uid`,`_owner`,`_secret`,`_callback`,`_state`,`_dt`) values ('FireRobot', 'FireRobot', '123456', 'http://127.0.0.1:8883/robot/recvmsg', 0, 1);\n"
  },
  {
    "path": "broker/migrate/mysql/V60__modify_messages_target.sql",
    "content": "alter table `t_messages` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_0` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_1` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_2` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_3` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_4` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_5` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_6` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_7` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_8` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_9` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_10` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_11` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_12` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_13` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_14` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_15` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_16` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_17` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_18` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_19` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_20` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_21` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_22` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_23` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_24` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_25` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_26` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_27` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_28` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_29` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_30` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_31` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_32` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_33` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_34` modify column `_target` varchar(129) NOT NULL;\nalter table `t_messages_35` modify column `_target` varchar(129) NOT NULL;\n"
  },
  {
    "path": "broker/migrate/mysql/V61__session_add_ip_column.sql",
    "content": "ALTER TABLE `t_user_session` ADD COLUMN `_ip` varchar(40) DEFAULT '';\n"
  },
  {
    "path": "broker/migrate/mysql/V64__add_group_member_index.sql",
    "content": "CREATE INDEX `user_gid_type_index` ON `t_group_member` (`_gid`, `_type`);\n"
  },
  {
    "path": "broker/migrate/mysql/V65__create_conference_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_conference`;\nCREATE TABLE `t_conference` (\n  `_id` varchar(64) NOT NULL PRIMARY KEY,\n  `_des` varchar(64) NOT NULL,\n  `_pin` varchar(16) NOT NULL,\n  `_max_publishers` int(11) NOT NULL DEFAULT 0,\n  `_bitrate` int(11) NOT NULL DEFAULT 0,\n  `_advance` tinyint NOT NULL DEFAULT 0,\n  `_recording` tinyint NOT NULL DEFAULT 0,\n  `_create_dt` bigint(20) NOT NULL\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n"
  },
  {
    "path": "broker/migrate/mysql/V66__create_join_group_request_table.sql",
    "content": "\nDROP TABLE IF EXISTS `t_join_group_request`;\nCREATE TABLE `t_join_group_request` (\n  `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n  `_uid` varchar(64) NOT NULL,\n  `_gid` varchar(64) NOT NULL,\n  `_mid` varchar(64) NOT NULL,\n  `_request_uid` varchar(64) NOT NULL,\n  `_accept_uid` varchar(64) DEFAULT NULL,\n  `_reason` TEXT DEFAULT NULL,\n  `_extra` TEXT DEFAULT NULL,\n  `_status` tinyint NOT NULL DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  `_read_status` tinyint DEFAULT 0,\n  UNIQUE INDEX `join_group_request_key_index` (`_uid` DESC, `_gid` DESC, `_mid` DESC, `_request_uid` DESC),\n  INDEX `join_group_request_gm_index` (`_gid` DESC, `_mid` DESC),\n  INDEX `join_group_request_sync_index` (`_uid` DESC, `_dt` DESC)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n"
  },
  {
    "path": "broker/migrate/mysql/V67__create_friend_index.sql",
    "content": "alter table t_friend add index `friend_uid_index` (`_friend_uid`);\n"
  },
  {
    "path": "broker/migrate/mysql/V6__add_friend_alias.sql",
    "content": "alter table t_friend add column `_alias` varchar(64) DEFAULT NULL;\n"
  },
  {
    "path": "broker/migrate/mysql/V7__add_createtime_user_group_table.sql",
    "content": "alter table t_user add column `_createTime` TIMESTAMP default CURRENT_TIMESTAMP;\nalter table t_group add column `_createTime` TIMESTAMP default CURRENT_TIMESTAMP;\n"
  },
  {
    "path": "broker/migrate/mysql/V8__add_content_type_in_messages.sql",
    "content": "alter table `t_messages_0` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_1` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_2` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_3` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_4` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_5` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_6` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_7` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_8` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_9` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_10` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_11` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_12` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_13` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_14` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_15` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_16` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_17` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_18` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_19` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_20` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_21` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_22` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_23` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_24` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_25` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_26` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_27` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_28` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_29` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_30` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_31` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_32` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_33` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_34` add column `_content_type` int(11) NOT NULL DEFAULT '0';\nalter table `t_messages_35` add column `_content_type` int(11) NOT NULL DEFAULT '0';\n"
  },
  {
    "path": "broker/migrate/mysql/V9__add_sensitive_messages.sql",
    "content": "\nDROP TABLE IF EXISTS `t_sensitive_messages`;\nCREATE TABLE `t_sensitive_messages` (\n    `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,\n    `_mid` bigint(20) NOT NULL,\n    `_from` varchar(64) NOT NULL,\n    `_type` tinyint NOT NULL DEFAULT 0,\n    `_target` varchar(64) NOT NULL,\n    `_line` int(11) NOT NULL DEFAULT 0,\n    `_data` BLOB NOT NULL,\n    `_searchable_key` TEXT DEFAULT NULL,\n    `_dt` DATETIME NOT NULL,\n    `_content_type` int(11) NOT NULL DEFAULT '0',\n    INDEX `message_uid_index` (`_mid` DESC)\n  )\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n"
  },
  {
    "path": "broker/migrate/重要！！！必看！！！.txt",
    "content": "程序会自动创建数据库和执行migrate里的数据库，不需要手动创建库和执行sql语句。\n\n数据库版本管理使用了flyway，flyway进行数据库升级时会校验数据库脚本的有效性，如果修改过这里的脚本，下次升级时就会失败。\n\n强烈不建议修改数据库表结构，如果有内容（比如默认用户或者默认机器人的属性）需要修改，可以等数据库升级完成后，通过命令行或者数据库客户端进行修改。\n由于服务具有缓存，一般修改过数据库内容后要重启后才能生效。\n"
  },
  {
    "path": "broker/nginx/imserver.conf",
    "content": "upstream imserver  {\n    server 127.0.0.1:8080; #Apache\n}\n\nserver {\n    listen 80;\n    server_name  www.wildfirechat.cn;\n\n    root   html;\n    index  index.html index.htm index.php;\n\n    #同步服务设置\n    location /route {\n        proxy_set_header  Host  $host;\n        proxy_set_header  X-real-ip $remote_addr;\n        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_pass  http://imserver;\n    }\n\n    #客户端短连接业务\n    location /im {\n        proxy_set_header  Host  $host;\n        proxy_set_header  X-real-ip $remote_addr;\n        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_pass  http://imserver;\n    }\n\n    #版本检查/api/version，可以删掉\n    location /api {\n        proxy_pass  http://imserver;\n    }\n\n    #内置文件上传和下载\n    location /fs {\n        client_max_body_size 200M;\n        proxy_set_header  Host  $host;\n        proxy_set_header  X-real-ip $remote_addr;\n        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_pass  http://imserver;\n    }\n\n    #机器人API\n    location /robot {\n        proxy_set_header  Host  $host;\n        proxy_set_header  X-real-ip $remote_addr;\n        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_pass  http://imserver;\n    }\n\n    #频道API\n    location /channel {\n        proxy_set_header  Host  $host;\n        proxy_set_header  X-real-ip $remote_addr;\n        proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_pass  http://imserver;\n    }\n}\n"
  },
  {
    "path": "broker/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <relativePath>../</relativePath>\n        <artifactId>wildfirechat-parent</artifactId>\n        <groupId>cn.wildfirechat</groupId>\n        <version>1.4.5</version>\n    </parent>\n\n    <artifactId>moquette-broker</artifactId>\n    <packaging>jar</packaging>\n    <name>Moquette - broker</name>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <bintray.package>io.moquette.moquette-broker</bintray.package>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>cn.wildfirechat</groupId>\n            <artifactId>common</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.logging.log4j</groupId>\n            <artifactId>log4j-core</artifactId>\n            <version>2.17.2</version>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.logging.log4j</groupId>\n            <artifactId>log4j-api</artifactId>\n            <version>2.17.2</version>\n        </dependency>\n        <!--用于与slf4j保持桥接-->\n        <dependency>\n            <groupId>org.apache.logging.log4j</groupId>\n            <artifactId>log4j-slf4j2-impl</artifactId>\n            <version>2.22.1</version>\n        </dependency>\n        <!-- slf4j核心包-->\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n            <version>2.0.12</version>\n        </dependency>\n        <dependency>\n            <groupId>com.lmax</groupId>\n            <artifactId>disruptor</artifactId>\n            <version>3.4.1</version>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n            <version>8.0.28</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.googlecode.json-simple</groupId>\n            <artifactId>json-simple</artifactId>\n            <version>1.1.1</version>\n        </dependency>\n\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <version>4.13.2</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.google.protobuf</groupId>\n            <artifactId>protobuf-java</artifactId>\n            <version>3.25.3</version>\n        </dependency>\n\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-common</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-buffer</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-handler</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpclient</artifactId>\n            <version>4.5.13</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpcore</artifactId>\n            <version>4.4.1</version>\n        </dependency>\n\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-codec-http</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-transport-native-epoll</artifactId>\n            <version>${netty.version}</version>\n            <classifier>linux-x86_64</classifier>\n<!--            <classifier>linux-aarch_64</classifier>-->\n        </dependency>\n\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n            <version>1.13</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.hazelcast</groupId>\n            <artifactId>hazelcast</artifactId>\n            <version>3.11.5</version>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.hutool</groupId>\n            <artifactId>hutool-all</artifactId>\n            <version>5.8.26</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.mchange</groupId>\n            <artifactId>c3p0</artifactId>\n            <version>0.9.5.4</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.fusesource.mqtt-client</groupId>\n            <artifactId>mqtt-client</artifactId>\n            <version>1.12</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.eclipse.paho</groupId>\n            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>\n            <version>1.2.2</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.qiniu</groupId>\n            <artifactId>qiniu-java-sdk</artifactId>\n            <version>7.1.3</version>\n        </dependency>\n\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>2.7</version>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/com.h2database/h2 -->\n        <dependency>\n            <groupId>com.h2database</groupId>\n            <artifactId>h2</artifactId>\n            <version>1.4.197</version>\n            <scope>runtime</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>com.squareup.okhttp3</groupId>\n            <artifactId>okhttp</artifactId>\n            <version>4.12.0</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.flywaydb</groupId>\n            <artifactId>flyway-core</artifactId>\n            <version>5.2.4</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.mongodb</groupId>\n            <artifactId>mongo-java-driver</artifactId>\n            <version>3.4.1</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.tika</groupId>\n            <artifactId>tika-core</artifactId>\n            <version>2.4.1</version>\n        </dependency>\n    </dependencies>\n\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>pl.project13.maven</groupId>\n                <artifactId>git-commit-id-plugin</artifactId>\n                <version>2.1.5</version>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>revision</goal>\n                        </goals>\n                    </execution>\n                </executions>\n                <configuration>\n                    <!--日期格式;默认值:dd.MM.yyyy '@' HH:mm:ss z;-->\n                    <dateFormat>yyyyMMddHHmmss</dateFormat>\n                    <!--,构建过程中,是否打印详细信息;默认值:false;-->\n                    <verbose>true</verbose>\n                    <!-- \".git\"文件路径;默认值:${project.basedir}/.git; -->\n                    <dotGitDirectory>${project.basedir}/.git</dotGitDirectory>\n                    <!--若项目打包类型为pom,是否取消构建;默认值:true;-->\n                    <skipPoms>false</skipPoms>\n                    <!--是否生成\"git.properties\"文件;默认值:false;-->\n                    <generateGitPropertiesFile>true</generateGitPropertiesFile>\n                    <!--指定\"git.properties\"文件的存放路径(相对于${project.basedir}的一个路径);-->\n                    <generateGitPropertiesFilename>config/git.properties</generateGitPropertiesFilename>\n                    <!--\".git\"文件夹未找到时,构建是否失败;若设置true,则构建失败;若设置false,则跳过执行该目标;默认值:true;-->\n                    <failOnNoGitDirectory>false</failOnNoGitDirectory>\n\n                    <!--git描述配置,可选;由JGit提供实现;-->\n                    <gitDescribe>\n                        <!--是否生成描述属性-->\n                        <skip>false</skip>\n                        <!--提交操作未发现tag时,仅打印提交操作ID,-->\n                        <always>false</always>\n                        <!--提交操作ID显式字符长度,最大值为:40;默认值:7;\n                            0代表特殊意义;后面有解释;\n                        -->\n                        <abbrev>7</abbrev>\n                        <!--构建触发时,代码有修改时(即\"dirty state\"),添加指定后缀;默认值:\"\";-->\n                        <dirty>-dirty</dirty>\n                        <!--always print using the \"tag-commits_from_tag-g_commit_id-maybe_dirty\" format, even if \"on\" a tag.\n                            The distance will always be 0 if you're \"on\" the tag.\n                        -->\n                        <forceLongFormat>false</forceLongFormat>\n                    </gitDescribe>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "broker/src/main/java/cn/wildfirechat/push/PushMessage.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.push;\n\n\npublic class PushMessage {\n    public String sender;\n    public String senderName;\n    public String senderPortrait;\n    public int convType;\n    public String target;\n    public String targetName;\n    public String targetPortrait;\n    public String userId;\n    public int line;\n    public int cntType;\n    public long serverTime;\n    //消息的类型，普通消息通知栏；voip要透传。\n    public int pushMessageType;\n    //推送类型，android推送分为小米/华为/魅族等。ios分别为开发和发布。\n    public int pushType;\n    public String pushContent;\n    public String pushData;\n    public int unReceivedMsg;\n    public int mentionedType;\n    public String packageName;\n    public String deviceToken;\n    public String voipDeviceToken;\n    public boolean isHiddenDetail;\n    public String language;\n    public boolean republish;\n    public long messageId;\n    public long callStartUid;\n    public int existBadgeNumber;\n\n    public PushMessage(String sender, int conversationType, String target, int line, int messageContentType, long serverTime, String senderName, String senderPortrait, String targetName, String targetPortrait, int unReceivedMsg, int mentionedType, boolean isHiddenDetail, String language) {\n        this.sender = sender;\n        this.convType = conversationType;\n        this.target = target;\n        this.senderName = senderName;\n        this.senderPortrait = senderPortrait;\n        this.targetName = targetName;\n        this.targetPortrait = targetPortrait;\n        this.line = line;\n        this.cntType = messageContentType;\n        this.serverTime = serverTime;\n        this.unReceivedMsg = unReceivedMsg;\n        if (cntType == 400 || cntType == 406) {\n            this.pushMessageType = PushServer.PushMessageType.PUSH_MESSAGE_TYPE_VOIP_INVITE;\n        } else if(cntType == 402) {\n            this.pushMessageType = PushServer.PushMessageType.PUSH_MESSAGE_TYPE_VOIP_BYE;\n        } else if(cntType == 401) {\n            this.pushMessageType = PushServer.PushMessageType.PUSH_MESSAGE_TYPE_VOIP_ANSWER;\n        } else if(cntType == 80) {\n            this.pushMessageType = PushServer.PushMessageType.PUSH_MESSAGE_TYPE_RECALLED;\n        } else if(cntType == 81) {\n            this.pushMessageType = PushServer.PushMessageType.PUSH_MESSAGE_TYPE_DELETED;\n        } else {\n            this.pushMessageType = PushServer.PushMessageType.PUSH_MESSAGE_TYPE_NORMAL;\n        }\n\n        this.mentionedType = mentionedType;\n        this.isHiddenDetail = isHiddenDetail;\n        this.language = language;\n        this.republish = messageContentType == 80 || messageContentType == 81;\n    }\n    public PushMessage(String sender, String target, long serverTime, String senderName, int unReceivedMsg, String language, int pushMessageType) {\n        this.sender = sender;\n        this.target = target;\n        this.senderName = senderName;\n        this.serverTime = serverTime;\n        this.unReceivedMsg = unReceivedMsg;\n        this.pushMessageType = pushMessageType;\n        this.language = language;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/cn/wildfirechat/push/PushServer.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.push;\n\nimport cn.wildfirechat.common.IMExceptionEvent;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.moquette.server.config.IConfig;\nimport io.moquette.spi.ISessionsStore;\nimport io.netty.util.internal.StringUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.HttpUtils;\nimport win.liyufan.im.Utility;\n\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport static io.moquette.BrokerConstants.*;\nimport static win.liyufan.im.HttpUtils.HttpPostType.POST_TYPE_Push;\n\npublic class PushServer {\n    private static final Logger LOG = LoggerFactory.getLogger(PushServer.class);\n    protected static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();\n    public interface PushMessageType {\n        int PUSH_MESSAGE_TYPE_NORMAL = 0;\n        int PUSH_MESSAGE_TYPE_VOIP_INVITE = 1;\n        int PUSH_MESSAGE_TYPE_VOIP_BYE = 2;\n        int PUSH_MESSAGE_TYPE_FRIEND_REQUEST = 3;\n        int PUSH_MESSAGE_TYPE_VOIP_ANSWER = 4;\n        int PUSH_MESSAGE_TYPE_RECALLED = 5;\n        int PUSH_MESSAGE_TYPE_DELETED = 6;\n    }\n\n    private static PushServer INSTANCE = new PushServer();\n    private ISessionsStore sessionsStore;\n    private static ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*5);\n\n    private String androidPushServerUrl;\n    private String iOSPushServerUrl;\n    private String harmonyPushServerUrl;\n\n    private PushServer() {\n    }\n\n    public static PushServer getServer() {\n        return INSTANCE;\n    }\n\n    public void init(IConfig config, ISessionsStore sessionsStore) {\n        this.sessionsStore = sessionsStore;\n        this.androidPushServerUrl = config.getProperty(PUSH_ANDROID_SERVER_ADDRESS);\n        this.iOSPushServerUrl = config.getProperty(PUSH_IOS_SERVER_ADDRESS);\n        this.harmonyPushServerUrl = config.getProperty(PUSH_HARMONY_SERVER_ADDRESS);\n    }\n\n    public void pushMessage(PushMessage pushMessage, String deviceId, String pushContent) {\n        LOG.info(\"try to delivery push diviceId = {}, conversationType = {}, pushContent = {}\", deviceId, pushMessage.convType, pushContent);\n        executorService.execute(() ->{\n                try {\n                    pushMessageInternel(pushMessage, deviceId, pushContent);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, IMExceptionEvent.EventType.PUSH_SERVER_Exception);\n                }\n            });\n    }\n\n    private void pushMessageInternel(PushMessage pushMessage, String deviceId, String pushContent) {\n        if (pushMessage.pushMessageType == PushMessageType.PUSH_MESSAGE_TYPE_NORMAL && StringUtil.isNullOrEmpty(pushContent)) {\n            LOG.info(\"push content empty, deviceId {}\", deviceId);\n            return;\n        }\n\n        MemorySessionStore.Session session = sessionsStore.getSession(deviceId);\n        if (StringUtil.isNullOrEmpty(session.getDeviceToken())) {\n            LOG.warn(\"Device token is empty for device {}\", deviceId);\n            return;\n        }\n\n        pushMessage.packageName = session.getAppName();\n        pushMessage.pushType = session.getPushType();\n        pushMessage.pushContent = pushContent;\n        pushMessage.deviceToken = session.getDeviceToken();\n        pushMessage.userId = session.getUsername();\n        if (session.getPlatform() == ProtoConstants.Platform.Platform_iOS ||\n            session.getPlatform() == ProtoConstants.Platform.Platform_iPad ||\n            session.getPlatform() == ProtoConstants.Platform.Platform_Android ||\n            session.getPlatform() == ProtoConstants.Platform.Platform_APad ||\n            session.getPlatform() == ProtoConstants.Platform.Platform_Harmony ||\n            session.getPlatform() == ProtoConstants.Platform.Platform_HarmonyPad ||\n            session.getPlatform() == ProtoConstants.Platform.Platform_AppleTV ||\n            session.getPlatform() == ProtoConstants.Platform.Platform_AndroidTV ||\n            session.getPlatform() == ProtoConstants.Platform.Platform_HarmonyTV ||\n            session.getPlatform() == ProtoConstants.Platform.Platform_HarmonyWearable ||\n            session.getPlatform() == ProtoConstants.Platform.Platform_AndroidWearable\n        ) {\n            String url = androidPushServerUrl;\n            if (session.getPlatform() == ProtoConstants.Platform.Platform_iOS || session.getPlatform() == ProtoConstants.Platform.Platform_iPad || session.getPlatform() == ProtoConstants.Platform.Platform_AppleTV) {\n                url = iOSPushServerUrl;\n                pushMessage.voipDeviceToken = session.getVoipDeviceToken();\n            } else if (session.getPlatform() == ProtoConstants.Platform.Platform_Harmony || session.getPlatform() == ProtoConstants.Platform.Platform_HarmonyPad || session.getPlatform() == ProtoConstants.Platform.Platform_HarmonyWearable || session.getPlatform() == ProtoConstants.Platform.Platform_HarmonyTV) {\n                url = harmonyPushServerUrl;\n            }\n            HttpUtils.httpJsonPost(url, gson.toJson(pushMessage, pushMessage.getClass()), POST_TYPE_Push);\n        } else {\n            LOG.info(\"Not mobile platform {}\", session.getPlatform());\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/cn/wildfirechat/server/Server.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.server;\n\nimport java.io.IOException;\n\npublic class Server {\n    public static void main(String[] args) throws IOException {\n        io.moquette.server.Server.start(args);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/cn/wildfirechat/server/ThreadPoolExecutorWrapper.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.server;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.concurrent.ScheduledExecutorService;\nimport java.util.concurrent.atomic.AtomicInteger;\n\npublic class ThreadPoolExecutorWrapper {\n    private static final Logger LOG = LoggerFactory.getLogger(ThreadPoolExecutorWrapper.class);\n    private final ScheduledExecutorService executor;\n    private final int count;\n    private final AtomicInteger runCounter;\n    private final String name;\n\n    public ThreadPoolExecutorWrapper(ScheduledExecutorService executor, int count, String name) {\n        this.executor = executor;\n        this.count = count;\n        this.runCounter = new AtomicInteger();\n        this.name = name;\n    }\n\n    public void execute(Runnable task) {\n        int startCount = runCounter.incrementAndGet();\n        LOG.debug(\"Submit task and current task count {}\", startCount);\n        final long startTime = System.currentTimeMillis();\n        executor.execute(() -> {\n            try {\n                task.run();\n            } catch (Exception e) {\n                e.printStackTrace();\n                LOG.info(\"execute error = {}\", e.toString());\n            } finally {\n                int endCount = runCounter.decrementAndGet();\n                LOG.debug(\"Finish task and current task count {} use time {}\", endCount, System.currentTimeMillis()-startTime);\n            }\n        });\n    }\n\n    public void shutdown() {\n        executor.shutdown();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/LoFileServer.java",
    "content": "package com.xiaoleilu.loServer;\n\nimport cn.hutool.core.date.DateUtil;\nimport com.xiaoleilu.loServer.action.Action;\nimport com.xiaoleilu.loServer.action.ClassUtil;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.ActionHandler;\nimport com.xiaoleilu.loServer.handler.HttpFileServerHandler;\nimport io.moquette.spi.IMessagesStore;\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.http.HttpObjectAggregator;\nimport io.netty.handler.codec.http.HttpRequestDecoder;\nimport io.netty.handler.codec.http.HttpResponseEncoder;\nimport io.netty.handler.codec.http.HttpServerCodec;\nimport io.netty.handler.stream.ChunkedWriteHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\n\n/**\n * LoServer starter<br>\n * 用于启动服务器的主对象<br>\n * 使用LoServer.start()启动服务器<br>\n * 服务的Action类和端口等设置在ServerSetting中设置\n * @author Looly\n *\n */\npublic class LoFileServer {\n    private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(LoFileServer.class);\n\tprivate int port;\n    private IMessagesStore messagesStore;\n    private Channel channel;\n\n    public LoFileServer(int port, IMessagesStore messagesStore) {\n        this.port = port;\n        this.messagesStore = messagesStore;\n    }\n\n    /**\n\t * 启动服务\n\t * @throws InterruptedException \n\t */\n\tpublic void start() throws InterruptedException {\n\t\tlong start = System.currentTimeMillis();\n\t\t\n\t\t// Configure the server.\n\t\tfinal EventLoopGroup bossGroup = new NioEventLoopGroup(1);\n\t\tfinal EventLoopGroup workerGroup = new NioEventLoopGroup();\n\n\t\ttry {\n\t\t\tfinal ServerBootstrap b = new ServerBootstrap();\n\t\t\tb.group(bossGroup, workerGroup)\n                .channel(NioServerSocketChannel.class)\n                .option(ChannelOption.SO_BACKLOG, 1024) // 服务端可连接队列大小\n                .option(ChannelOption.SO_KEEPALIVE, true)\n                .option(ChannelOption.SO_REUSEADDR, true)\n                .option(ChannelOption.TCP_NODELAY, true)\n                .option(ChannelOption.SO_SNDBUF, 1024*1024*10)\n                .option(ChannelOption.SO_RCVBUF, 1024*1024*10)\n                .childHandler(new ChannelInitializer<SocketChannel>() {\n                    @Override\n                    protected void initChannel(SocketChannel socketChannel) throws Exception {\n                        socketChannel.pipeline().addLast(new HttpRequestDecoder());\n                        socketChannel.pipeline().addLast(new HttpResponseEncoder());\n                        socketChannel.pipeline().addLast(new ChunkedWriteHandler());\n                        socketChannel.pipeline().addLast(new HttpObjectAggregator(100 * 1024 * 1024));\n                        socketChannel.pipeline().addLast(new HttpFileServerHandler());\n                    }\n                });\n\t\t\t\n\t\t\tchannel = b.bind(port).sync().channel();\n\t\t\tLogger.info(\"***** Welcome To LoServer on port [{}], startting spend {}ms *****\", port, DateUtil.spendMs(start));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Logger.error(\"端口 {} 已经被占用。请检查该端口被那个程序占用，找到程序停掉。\\n查找端口被那个程序占用的命令是: netstat -tunlp | grep {}\", port, port);\n            System.out.println(\"端口 \" + port + \" 已经被占用。请检查该端口被那个程序占用，找到程序停掉。\\n查找端口被那个程序占用的命令是: netstat -tunlp | grep \" + port);\n            System.exit(-1);\n        }\n\t}\n    public void shutdown() {\n        if (this.channel != null) {\n            this.channel.close();\n            try {\n                this.channel.closeFuture().sync();\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/LoServer.java",
    "content": "package com.xiaoleilu.loServer;\n\nimport cn.hutool.core.date.DateUtil;\nimport com.xiaoleilu.loServer.action.Action;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.AdminActionHandler;\nimport com.xiaoleilu.loServer.handler.IMActionHandler;\nimport io.moquette.spi.IMessagesStore;\nimport io.moquette.spi.ISessionsStore;\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelInitializer;\nimport io.netty.channel.ChannelOption;\nimport io.netty.channel.EventLoopGroup;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.http.HttpObjectAggregator;\nimport io.netty.handler.codec.http.HttpRequestDecoder;\nimport io.netty.handler.codec.http.HttpResponseEncoder;\nimport io.netty.handler.stream.ChunkedWriteHandler;\nimport com.xiaoleilu.loServer.action.ClassUtil;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.Utility;\n\nimport java.io.IOException;\n\n/**\n * LoServer starter<br>\n * 用于启动服务器的主对象<br>\n * 使用LoServer.start()启动服务器<br>\n * 服务的Action类和端口等设置在ServerSetting中设置\n * @author Looly\n *\n */\npublic class LoServer {\n    private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(LoServer.class);\n\tprivate int port;\n    private int adminPort;\n    private IMessagesStore messagesStore;\n    private ISessionsStore sessionsStore;\n    private Channel channel;\n    private Channel adminChannel;\n\n    public LoServer(int port, int adminPort, IMessagesStore messagesStore, ISessionsStore sessionsStore) {\n        this.port = port;\n        this.adminPort = adminPort;\n        this.messagesStore = messagesStore;\n        this.sessionsStore = sessionsStore;\n    }\n\n    /**\n\t * 启动服务\n\t * @throws InterruptedException \n\t */\n\tpublic void start() throws InterruptedException {\n\t\tlong start = System.currentTimeMillis();\n\t\t\n\t\t// Configure the server.\n\t\tfinal EventLoopGroup bossGroup = new NioEventLoopGroup(2);\n\t\tfinal EventLoopGroup workerGroup = new NioEventLoopGroup();\n\n        registerAllAction();\n\n        int bindingPort = port;\n\t\ttry {\n\t\t\tfinal ServerBootstrap b = new ServerBootstrap();\n            final ServerBootstrap adminB = new ServerBootstrap();\n\t\t\tb.group(bossGroup, workerGroup)\n                .channel(NioServerSocketChannel.class)\n                .option(ChannelOption.SO_BACKLOG, 10240) // 服务端可连接队列大小\n                .childOption(ChannelOption.SO_KEEPALIVE, true)\n                .option(ChannelOption.SO_REUSEADDR, true)\n                .childOption(ChannelOption.TCP_NODELAY, true)\n                .childOption(ChannelOption.SO_SNDBUF, 1024*64)\n                .childOption(ChannelOption.SO_RCVBUF, 1024*64)\n                .childHandler(new ChannelInitializer<SocketChannel>() {\n                    @Override\n                    protected void initChannel(SocketChannel socketChannel) throws Exception {\n                        socketChannel.pipeline().addLast(new HttpRequestDecoder());\n                        socketChannel.pipeline().addLast(new HttpResponseEncoder());\n                        socketChannel.pipeline().addLast(new ChunkedWriteHandler());\n                        socketChannel.pipeline().addLast(new HttpObjectAggregator(100 * 1024 * 1024));\n                        socketChannel.pipeline().addLast(new IMActionHandler(messagesStore, sessionsStore));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\n\t\t\tchannel = b.bind(port).sync().channel();\n\n\n            bindingPort = adminPort;\n            adminB.group(bossGroup, workerGroup)\n                .channel(NioServerSocketChannel.class)\n                .option(ChannelOption.SO_BACKLOG, 10240) // 服务端可连接队列大小\n                .childOption(ChannelOption.SO_KEEPALIVE, true)\n                .option(ChannelOption.SO_REUSEADDR, true)\n                .childOption(ChannelOption.TCP_NODELAY, true)\n                .childOption(ChannelOption.SO_SNDBUF, 1024*64)\n                .childOption(ChannelOption.SO_RCVBUF, 1024*64)\n                .childHandler(new ChannelInitializer<SocketChannel>() {\n                    @Override\n                    protected void initChannel(SocketChannel socketChannel) throws Exception {\n                        socketChannel.pipeline().addLast(new HttpRequestDecoder());\n                        socketChannel.pipeline().addLast(new HttpResponseEncoder());\n                        socketChannel.pipeline().addLast(new ChunkedWriteHandler());\n                        socketChannel.pipeline().addLast(new HttpObjectAggregator(100 * 1024 * 1024));\n                        socketChannel.pipeline().addLast(new AdminActionHandler(messagesStore, sessionsStore));\n                    }\n                });\n\n            adminChannel = adminB.bind(adminPort).sync().channel();\n\t\t\tLogger.info(\"***** Welcome To LoServer on port [{},{}], startting spend {}ms *****\", port, adminPort, DateUtil.spendMs(start));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Logger.error(\"端口 {} 已经被占用。请检查该端口被那个程序占用，找到程序停掉。\\n查找端口被那个程序占用的命令是: netstat -tunlp | grep {}\", bindingPort, bindingPort);\n            System.out.println(\"端口 \" + bindingPort + \" 已经被占用。请检查该端口被那个程序占用，找到程序停掉。\\n查找端口被那个程序占用的命令是: netstat -tunlp | grep \" + bindingPort);\n            System.exit(-1);\n        }\n\t}\n\n    public void shutdown() {\n        if (this.channel!= null) {\n            this.channel.close();\n            try {\n                this.channel.closeFuture().sync();\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        }\n\n        if (this.adminChannel != null) {\n            this.adminChannel.close();\n            try {\n                this.adminChannel.closeFuture().sync();\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    private void registerAllAction() {\n        try {\n            for (Class cls:ClassUtil.getAllAssignedClass(Action.class)\n                 ) {\n                if(cls.getAnnotation(Route.class) != null) {\n                    ServerSetting.setAction((Class<? extends Action>)cls);\n                }\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n            Utility.printExecption(Logger, e);\n        } catch (ClassNotFoundException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/RestResult.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer;\n\nimport cn.wildfirechat.common.ErrorCode;\n\npublic class RestResult {\n\n\n    int code;\n    String msg;\n    Object result;\n\n    public static RestResult ok(Object object) {\n        return resultOf(ErrorCode.ERROR_CODE_SUCCESS, ErrorCode.ERROR_CODE_SUCCESS.getMsg(), object);\n    }\n\n    public static RestResult ok() {\n        return resultOf(ErrorCode.ERROR_CODE_SUCCESS, ErrorCode.ERROR_CODE_SUCCESS.getMsg(), null);\n    }\n\n    public static RestResult resultOf(ErrorCode errorCode) {\n        return resultOf(errorCode, errorCode.msg, null);\n    }\n\n    public static RestResult resultOf(ErrorCode errorCode, String msg) {\n        return resultOf(errorCode, msg, null);\n    }\n\n    public static RestResult resultOf(ErrorCode errorCode, String msg, Object object) {\n        RestResult result = new RestResult();\n        result.code = errorCode.code;\n        result.msg = msg;\n        result.result = object;\n        return result;\n    }\n\n    public void setErrorCode(ErrorCode errorCode) {\n        setCode(errorCode.code);\n    }\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    public void setMsg(String msg) {\n        this.msg = msg;\n    }\n\n    public Object getResult() {\n        return result;\n    }\n\n    public void setResult(Object result) {\n        this.result = result;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/ServerSetting.java",
    "content": "package com.xiaoleilu.loServer;\n\nimport java.io.File;\nimport java.nio.charset.Charset;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport cn.hutool.core.io.FileUtil;\nimport cn.hutool.core.lang.Singleton;\nimport cn.hutool.core.util.StrUtil;\nimport com.xiaoleilu.loServer.action.Action;\nimport com.xiaoleilu.loServer.action.DefaultIndexAction;\nimport com.xiaoleilu.loServer.action.UnknownErrorAction;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.exception.ServerSettingException;\nimport com.xiaoleilu.loServer.filter.Filter;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 全局设定文件\n * @author xiaoleilu\n *\n */\npublic class ServerSetting {\n    private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(ServerSetting.class);\n\t\n\t//-------------------------------------------------------- Default value start\n\t/** 默认的字符集编码 */\n\tpublic final static String DEFAULT_CHARSET = \"utf-8\";\n\t\n\tpublic final static String MAPPING_ALL = \"/*\";\n\t\n\tpublic final static String MAPPING_ERROR = \"/_error\";\n\t//-------------------------------------------------------- Default value end\n\t\n\t/** 字符编码 */\n\tprivate static String charset = DEFAULT_CHARSET;\n\t/** 端口 */\n\tprivate static int port = 8090;\n\t/** 根目录 */\n\tprivate static File root;\n\t/** Filter映射表 */\n\tprivate static Map<String, Filter> filterMap = new ConcurrentHashMap<>();\n\t/** Action映射表 */\n\tprivate static Map<String, Class<? extends Action>> getActionMap = new ConcurrentHashMap<>();\n    private static Map<String, Class<? extends Action>> postActionMap = new ConcurrentHashMap<>();\n    private static Map<String, Class<? extends Action>> putActionMap = new ConcurrentHashMap<>();\n    private static Map<String, Class<? extends Action>> deleteActionMap = new ConcurrentHashMap<>();\n    private static Map<String, Class<? extends Action>> errorActionMap = new ConcurrentHashMap<>();\n\t\n\tstatic{\n        errorActionMap.put(StrUtil.SLASH, DefaultIndexAction.class);\n        errorActionMap.put(MAPPING_ERROR, UnknownErrorAction.class);\n\t}\n\t\n\t/**\n\t * @return 获取编码\n\t */\n\tpublic static String getCharset() {\n\t\treturn charset;\n\t}\n\t/**\n\t * @return 字符集\n\t */\n\tpublic static Charset charset() {\n\t\treturn Charset.forName(getCharset());\n\t}\n\t\n\t/**\n\t * 设置编码\n\t * @param charset 编码\n\t */\n\tpublic static void setCharset(String charset) {\n\t\tServerSetting.charset = charset;\n\t}\n\t\n\t/**\n\t * @return 监听端口\n\t */\n\tpublic static int getPort() {\n\t\treturn port;\n\t}\n\t/**\n\t * 设置监听端口\n\t * @param port 端口\n\t */\n\tpublic static void setPort(int port) {\n\t\tServerSetting.port = port;\n\t}\n\t\n\t//----------------------------------------------------------------------------------------------- Root start\n\t/**\n\t * @return 根目录\n\t */\n\tpublic static File getRoot() {\n\t\treturn root;\n\t}\n\t/**\n\t * @return 根目录\n\t */\n\tpublic static boolean isRootAvailable() {\n\t\tif(root != null && root.isDirectory() && root.isHidden() == false && root.canRead()){\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t/**\n\t * @return 根目录\n\t */\n\tpublic static String getRootPath() {\n\t\treturn FileUtil.getAbsolutePath(root);\n\t}\n\t/**\n\t * 根目录\n\t * @param root 根目录绝对路径\n\t */\n\tpublic static void setRoot(String root) {\n\t\tServerSetting.root = FileUtil.mkdir(root);\n        Logger.debug(\"Set root to [{}]\", ServerSetting.root.getAbsolutePath());\n\t}\n\t/**\n\t * 根目录\n\t * @param root 根目录绝对路径\n\t */\n\tpublic static void setRoot(File root) {\n\t\tif(root.exists() == false){\n\t\t\troot.mkdirs();\n\t\t}else if(root.isDirectory() == false){\n\t\t\tthrow new ServerSettingException(StrUtil.format(\"{} is not a directory!\", root.getPath()));\n\t\t}\n\t\tServerSetting.root = root;\n\t}\n\t//----------------------------------------------------------------------------------------------- Root end\n\t\n\t//----------------------------------------------------------------------------------------------- Filter start\n\t/**\n\t * @return 获取FilterMap\n\t */\n\tpublic static Map<String, Filter> getFilterMap() {\n\t\treturn filterMap;\n\t}\n\t/**\n\t * 获得路径对应的Filter\n\t * @param path 路径，为空时将获得 根目录对应的Action\n\t * @return Filter\n\t */\n\tpublic static Filter getFilter(String path){\n\t\tif(StrUtil.isBlank(path)){\n\t\t\tpath = StrUtil.SLASH;\n\t\t}\n\t\treturn getFilterMap().get(path.trim());\n\t}\n\t/**\n\t * 设置FilterMap\n\t * @param filterMap FilterMap\n\t */\n\tpublic static void setFilterMap(Map<String, Filter> filterMap) {\n\t\tServerSetting.filterMap = filterMap;\n\t}\n\t\n\t/**\n\t * 设置Filter类，已有的Filter类将被覆盖\n\t * @param path 拦截路径（必须以\"/\"开头）\n\t * @param filter Action类\n\t */\n\tpublic static void setFilter(String path, Filter filter) {\n\t\tif(StrUtil.isBlank(path)){\n\t\t\tpath = StrUtil.SLASH;\n\t\t}\n\t\t\n\t\tif(null == filter) {\n\t\t\tLogger.warn(\"Added blank action, pass it.\");\n\t\t\treturn;\n\t\t}\n\t\t//所有路径必须以 \"/\" 开头，如果没有则补全之\n\t\tif(false == path.startsWith(StrUtil.SLASH)) {\n\t\t\tpath = StrUtil.SLASH + path;\n\t\t}\n\t\t\n\t\tServerSetting.filterMap.put(path, filter);\n\t}\n\t\n\t/**\n\t * 设置Filter类，已有的Filter类将被覆盖\n\t * @param path 拦截路径（必须以\"/\"开头）\n\t * @param filterClass Filter类\n\t */\n\tpublic static void setFilter(String path, Class<? extends Filter> filterClass) {\n\t\tsetFilter(path, (Filter) Singleton.get(filterClass));\n\t}\n\t//----------------------------------------------------------------------------------------------- Filter end\n\t\n\t//----------------------------------------------------------------------------------------------- Action start\n\t/**\n\t * @return 获取ActionMap\n\t */\n\tpublic static Map<String, Class<? extends Action>> getActionMap(String method) {\n\t    if (method.equals(\"GET\")) {\n            return getActionMap;\n        } else if(method.equals(\"POST\")) {\n\t        return postActionMap;\n        } else if(method.equals(\"PUT\")) {\n\t        return putActionMap;\n        } else if(method.equals(\"DELETE\")) {\n\t        return deleteActionMap;\n        }\n\t\treturn getActionMap;\n\t}\n\n    public static Action getErrorAction(String path) {\n        Class<? extends Action> cls = errorActionMap.get(path);\n        if(cls != null) {\n            try {\n                return cls.newInstance();\n            } catch (InstantiationException e) {\n                e.printStackTrace();\n            } catch (IllegalAccessException e) {\n                e.printStackTrace();\n            }\n        }\n        return null;\n    }\n\n    /**\n\t * 获得路径对应的Action\n\t * @param path 路径，为空时将获得 根目录对应的Action\n\t * @return Action\n\t */\n\tpublic static Action getAction(String path, String method){\n\t\tif(StrUtil.isBlank(path)){\n\t\t\tpath = StrUtil.SLASH;\n\t\t}\n        Class<? extends Action> cls = getActionMap(method).get(path.trim());\n        if(cls != null) {\n            try {\n                return cls.newInstance();\n            } catch (InstantiationException e) {\n                e.printStackTrace();\n            } catch (IllegalAccessException e) {\n                e.printStackTrace();\n            }\n        }\n        return null;\n\t}\n\t\n\t/**\n\t * 增加Action类，已有的Action类将被覆盖<br>\n\t * 所有Action都是以单例模式存在的！\n\t * @param path 拦截路径（必须以\"/\"开头）\n\t * @param actionClass Action类\n\t */\n\tpublic static void setAction(String path, Class<? extends Action> actionClass) {\n        if(StrUtil.isBlank(path)){\n            path = StrUtil.SLASH;\n        }\n\n        if(null == actionClass) {\n            Logger.warn(\"Added blank action, pass it.\");\n            return;\n        }\n        //所有路径必须以 \"/\" 开头，如果没有则补全之\n        if(false == path.startsWith(StrUtil.SLASH)) {\n            path = StrUtil.SLASH + path;\n        }\n        String method = \"GET\";\n        HttpMethod methodAnnotation = actionClass.getAnnotation(HttpMethod.class);\n        if (methodAnnotation != null) {\n            method = methodAnnotation.value();\n        }\n        ServerSetting.getActionMap(method).put(path, actionClass);\n\t}\n\n\t/**\n\t * 增加Action类，已有的Action类将被覆盖<br>\n\t * 所有Action都是以单例模式存在的！\n\t * @param actionClass 带注解的Action类\n\t */\n\tpublic static void setAction(Class<? extends Action> actionClass) {\n        final Route route = actionClass.getAnnotation(Route.class);\n        if(route != null){\n            final String path = route.value();\n            if(StrUtil.isNotBlank(path)){\n                setAction(path, actionClass);\n                return;\n            }\n        }\n        throw new ServerSettingException(\"Can not find Route annotation,please add annotation to Action class!\");\n\t}\n\t//----------------------------------------------------------------------------------------------- Action start\n\t\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/Action.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action;\n\nimport cn.wildfirechat.common.IMExceptionEvent;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonSyntaxException;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.action.channel.ChannelAction;\nimport com.xiaoleilu.loServer.action.robot.RobotAction;\nimport com.xiaoleilu.loServer.annotation.RequireAuthentication;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.server.config.IConfig;\nimport io.moquette.spi.IMessagesStore;\nimport io.moquette.spi.ISessionsStore;\nimport io.moquette.spi.impl.Utils;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport cn.wildfirechat.common.ErrorCode;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.RateLimiter;\nimport win.liyufan.im.Utility;\n\nimport java.nio.charset.StandardCharsets;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\nimport static io.moquette.BrokerConstants.*;\n\n/**\n * 请求处理接口<br>\n * 当用户请求某个Path，则调用相应Action的doAction方法\n * @author Looly\n *\n */\n\nabstract public class Action {\n    private static final Logger LOG = LoggerFactory.getLogger(Action.class);\n    public static IMessagesStore messagesStore = null;\n    public static ISessionsStore sessionsStore = null;\n    protected static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();\n    public ChannelHandlerContext ctx;\n\n    protected static RateLimiter adminLimiter = null;\n    protected static RateLimiter robotLimiter = null;\n    protected static RateLimiter channelLimiter = null;\n\n    protected static boolean closeApiVersion = false;\n\n    public static void init(IConfig config) {\n        int adminRate = 10000;\n        int robotRate = 1000;\n        int channelRate = 1000;\n\n        try {\n            adminRate = Integer.parseInt(config.getProperty(HTTP_ADMIN_RATE_LIMIT, \"10000\"));\n        } catch (NumberFormatException e) {\n\n        }\n        try {\n            robotRate = Integer.parseInt(config.getProperty(HTTP_ROBOT_RATE_LIMIT, \"1000\"));\n        } catch (NumberFormatException e) {\n\n        }\n        try {\n            channelRate = Integer.parseInt(config.getProperty(HTTP_CHANNEL_RATE_LIMIT, \"1000\"));\n        } catch (NumberFormatException e) {\n\n        }\n        adminLimiter = new RateLimiter(10, adminRate);\n        robotLimiter = new RateLimiter(10, robotRate);\n        channelLimiter = new RateLimiter(10, channelRate);\n\n        try {\n            closeApiVersion = Boolean.parseBoolean(config.getProperty(HTTP_CLOSE_API_VERSION, \"false\"));\n        } catch (Exception e) {\n        }\n    }\n\n    protected class Result {\n        Object data;\n        ErrorCode errorCode;\n\n        public Result(ErrorCode errorCode) {\n            this.errorCode = errorCode;\n        }\n\n        public Result(ErrorCode errorCode, Object data) {\n            this.data = data;\n            this.errorCode = errorCode;\n        }\n\n        public Object getData() {\n            return data;\n        }\n\n        public ErrorCode getErrorCode() {\n            return errorCode;\n        }\n    }\n\n    protected interface ApiCallback {\n        Result onResult(byte[] response);\n    }\n\n    public ErrorCode preAction(Request request, Response response) {\n        if (getClass().getAnnotation(RequireAuthentication.class) != null) {\n            //do authentication\n        }\n\n        return ERROR_CODE_SUCCESS;\n    }\n\tpublic boolean doAction(Request request, Response response) {\n        ErrorCode errorCode = preAction(request, response);\n        boolean isSync = true;\n        if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n            //事务逻辑有缺陷，先注释掉\n//            if (isTransactionAction() && !(this instanceof IMAction)) {\n//                DBUtil.beginTransaction();\n//                try {\n//                    action(request, response);\n//                    DBUtil.commit();\n//                } catch (Exception e) {\n//                    e.printStackTrace();\n//                    DBUtil.roolback();\n//                    throw e;\n//                }\n//            } else {\n            isSync = action(request, response);\n//            }\n        } else {\n            response.setStatus(HttpResponseStatus.OK);\n            if (errorCode == null) {\n                errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n            }\n\n            RestResult result = RestResult.resultOf(errorCode, errorCode.getMsg(), RestResult.resultOf(errorCode));\n            response.setContent(gson.toJson(result));\n            response.send();\n        }\n\n        return isSync;\n    }\n    public boolean isTransactionAction() {\n        return false;\n    }\n    abstract public boolean action(Request request, Response response);\n\n    protected <T> T getRequestBody(HttpRequest request, Class<T> cls) {\n        if (request instanceof FullHttpRequest) {\n            FullHttpRequest fullHttpRequest = (FullHttpRequest) request;\n            byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());\n            String content = new String(bytes, StandardCharsets.UTF_8);//contribute by JiaRG from github\n\n            try {\n                T t = gson.fromJson(content, cls);\n                return t;\n            } catch (JsonSyntaxException e) {\n                e.printStackTrace();\n                LOG.error(\"Object {} from json {} failure\", cls.getName(), content);\n                int exception = IMExceptionEvent.EventType.ADMIN_API_Exception;\n                if (this instanceof RobotAction) {\n                    exception = IMExceptionEvent.EventType.ROBOT_API_Exception;\n                } else if (this instanceof ChannelAction) {\n                    exception = IMExceptionEvent.EventType.CHANNEL_API_Exception;\n                }\n                Utility.printExecption(LOG, e, exception);\n                throw new RuntimeException(e);\n            }\n        }\n        return null;\n    }\n\n    protected void setResponseContent(RestResult result, Response response) {\n        response.setStatus(HttpResponseStatus.OK);\n        response.setContent(gson.toJson(result));\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/CheckTokenAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action;\n\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.moquette.spi.security.Tokenor;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport win.liyufan.im.GitRepositoryState;\nimport win.liyufan.im.RateLimiter;\nimport win.liyufan.im.Utility;\n\nimport java.io.IOException;\n\n@Route(\"/api/verify_token\")\n@HttpMethod(\"GET\")\npublic class CheckTokenAction extends Action {\n    private final RateLimiter mLimitCounter = new RateLimiter(10, 1);\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            if(closeApiVersion) {\n                response.sendError(HttpResponseStatus.NOT_FOUND, \"404 Not found!\");\n                return true;\n            }\n\n            response.setStatus(HttpResponseStatus.OK);\n            String userId = request.getParam(\"userId\");\n            String clientId = request.getParam(\"clientId\");\n            String token = request.getParam(\"token\");\n\n            String result = \"这是个检查token有效性的接口，如果客户端无法连接成功，可以使用这个接口检查token是否正确。\\n\";\n            result += \"使用方法是在浏览器中输入http://imserverip/api/verify_token?userId=${userId}&clientId=${clientId}&token=${token}。\\n\";\n            result += \"例如：http://localhost/api/verify_token?userId=123&clientId=456&token=789。\\n\";\n            result += \"特别注意的是：必须使用正确的clientId，clientId必须是在测试手机上调用im接口获取。不用手机上获取到的clientId也都是不同的，一定不能用错！！！\\n\\n\\n\";\n\n            if (StringUtil.isNullOrEmpty(userId)) {\n                result += \"错误，userId为空\";\n            } else if (StringUtil.isNullOrEmpty(clientId)) {\n                result += \"错误，clientId为空\";\n            } else if (StringUtil.isNullOrEmpty(token)) {\n                result += \"错误，token为空\";\n            } else if(!mLimitCounter.isGranted(\"verify_token\")) {\n                result += \"接口请求超频！接口限制每10秒只能验证一次！\";\n            } else {\n                MemorySessionStore.Session session = sessionsStore.getSession(clientId);\n                if (session == null) {\n                    result += \"错误，session不存在。请确认token是从本服务通过getToken接口获取的，另外请确认clientId是否正确\";\n                } else if (session.getDeleted() == 1) {\n                    result += \"错误，session已经被清除，请确认当前客户没有多端登录或者主动退出\";\n                } else if(!session.getUsername().equals(userId)) {\n                    result += \"错误，当前客户端的登录用户不是\" + userId + \"。这一般发生在当前clientId又为其它用户获取过token\";\n                } else {\n                    String id = Tokenor.getUserId(token.getBytes());\n                    if (id == null) {\n                        result += \"错误，无效的token\";\n                    } else if(!id.equals(userId)) {\n                        result += \"错误，改token是用户\" + id + \"的\";\n                    } else {\n                        result += \"恭喜，您的信息是正确的\";\n                    }\n                }\n            }\n            response.setContent(result);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/ClassUtil.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\npublic class ClassUtil {\n\n    /**\n     * 获取同一路径下所有子类或接口实现类\n     *\n     * @param cls\n     * @return\n     * @throws IOException\n     * @throws ClassNotFoundException\n     */\n    public static List<Class<?>> getAllAssignedClass(Class<?> cls) throws IOException,\n        ClassNotFoundException {\n        List<Class<?>> classes = new ArrayList<Class<?>>();\n        for (Class<?> c : getClasses(cls)) {\n            if (cls.isAssignableFrom(c) && !cls.equals(c)) {\n                classes.add(c);\n            }\n        }\n        return classes;\n    }\n\n    /**\n     * 取得当前类路径下的所有类\n     *\n     * @param cls\n     * @return\n     * @throws IOException\n     * @throws ClassNotFoundException\n     */\n    public static List<Class<?>> getClasses(Class<?> cls) throws IOException,\n        ClassNotFoundException {\n        String pk = cls.getPackage().getName();\n//        String path = pk.replace('.', '/');\n//        ClassLoader classloader = Thread.currentThread().getContextClassLoader();\n//        URL url = classloader.getResource(path);\n//        String type = url.getProtocol();\n//\n//        System.out.println(\"the type is \" + type);\n//        System.out.println(url.getPath());\n//\n//        return getClasses(new File(url.getFile()), pk);\n        List<String> classNames = getClassName(pk, true);\n        List<Class<?>> classes = new ArrayList<>();\n        for (String className :\n             classNames) {\n            if (className.endsWith(\".class\")) {\n                className = className.substring(0, className.length() - 6);\n                className = className.substring(className.lastIndexOf(\"/\")+1, className.length());\n            }\n\n            classes.add(Class.forName(className));\n        }\n        return classes;\n    }\n\n    /**\n     * 迭代查找类\n     *\n     * @param dir\n     * @param pk\n     * @return\n     * @throws ClassNotFoundException\n     */\n    private static List<Class<?>> getClasses(File dir, String pk) throws ClassNotFoundException {\n        System.out.println(dir.getAbsolutePath());\n        List<Class<?>> classes = new ArrayList<Class<?>>();\n        if (!dir.exists()) {\n            return classes;\n        }\n        for (File f : dir.listFiles()) {\n            if (f.isDirectory()) {\n                classes.addAll(getClasses(f, pk + \".\" + f.getName()));\n            }\n            String name = f.getName();\n            if (name.endsWith(\".class\")) {\n                classes.add(Class.forName(pk + \".\" + name.substring(0, name.length() - 6)));\n            }\n        }\n        return classes;\n    }\n\n\n\n\n    /**\n     * 获取某包下所有类\n     * @param packageName 包名\n     * @param childPackage 是否遍历子包\n     * @return 类的完整名称\n     */\n    public static List<String> getClassName(String packageName, boolean childPackage) {\n        List<String> fileNames = null;\n        ClassLoader loader = Thread.currentThread().getContextClassLoader();\n        String packagePath = packageName.replace(\".\", \"/\");\n        URL url = loader.getResource(packagePath);\n        if (url != null) {\n            String type = url.getProtocol();\n            if (type.equals(\"file\")) {\n                fileNames = getClassNameByFile(url.getPath(), null, childPackage);\n            } else if (type.equals(\"jar\")) {\n                fileNames = getClassNameByJar(url.getPath(), childPackage);\n            }\n        } else {\n            fileNames = getClassNameByJars(((URLClassLoader) loader).getURLs(), packagePath, childPackage);\n        }\n        return fileNames;\n    }\n\n    /**\n     * 从项目文件获取某包下所有类\n     * @param filePath 文件路径\n     * @param className 类名集合\n     * @param childPackage 是否遍历子包\n     * @return 类的完整名称\n     */\n    private static List<String> getClassNameByFile(String filePath, List<String> className, boolean childPackage) {\n        List<String> myClassName = new ArrayList<String>();\n        File file = new File(filePath);\n        File[] childFiles = file.listFiles();\n        for (File childFile : childFiles) {\n            if (childFile.isDirectory()) {\n                if (childPackage) {\n                    myClassName.addAll(getClassNameByFile(childFile.getPath(), myClassName, childPackage));\n                }\n            } else {\n                String childFilePath = childFile.getPath();\n                if (childFilePath.endsWith(\".class\")) {\n                    if (childFilePath.indexOf(\"\\\\classes\") >= 0 || childFilePath.indexOf(\"/classes\") >= 0) {\n                        int start = childFilePath.indexOf(\"\\\\classes\");\n                        if (start == -1) {\n                            start = childFilePath.indexOf(\"/classes\");\n                        }\n                        childFilePath = childFilePath.substring(start + 9, childFilePath.lastIndexOf(\".\"));\n                    }\n                    childFilePath = childFilePath.replace(\"\\\\\", \".\");\n                    childFilePath = childFilePath.replace(\"/\", \".\");\n                    myClassName.add(childFilePath);\n                }\n            }\n        }\n\n        return myClassName;\n    }\n\n    /**\n     * 从jar获取某包下所有类\n     * @param jarPath jar文件路径\n     * @param childPackage 是否遍历子包\n     * @return 类的完整名称\n     */\n    private static List<String> getClassNameByJar(String jarPath, boolean childPackage) {\n        List<String> myClassName = new ArrayList<String>();\n        String[] jarInfo = jarPath.split(\"!\");\n        String jarFilePath = jarInfo[0].substring(jarInfo[0].indexOf(\"/\"));\n        String packagePath = jarInfo[1].substring(1);\n        try {\n            JarFile jarFile = new JarFile(jarFilePath);\n            Enumeration<JarEntry> entrys = jarFile.entries();\n            while (entrys.hasMoreElements()) {\n                JarEntry jarEntry = entrys.nextElement();\n                String entryName = jarEntry.getName();\n\n                if (entryName.endsWith(\".class\")) {\n                    if (childPackage) {\n                        if (entryName.startsWith(packagePath)) {\n                            entryName = entryName.replace(\"/\", \".\").substring(0, entryName.lastIndexOf(\".\"));\n                            myClassName.add(entryName);\n                        }\n                    } else {\n                        int index = entryName.lastIndexOf(\"/\");\n                        String myPackagePath;\n                        if (index != -1) {\n                            myPackagePath = entryName.substring(0, index);\n                        } else {\n                            myPackagePath = entryName;\n                        }\n                        if (myPackagePath.equals(packagePath)) {\n                            entryName = entryName.replace(\"/\", \".\").substring(0, entryName.lastIndexOf(\".\"));\n                            myClassName.add(entryName);\n                        }\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return myClassName;\n    }\n\n    /**\n     * 从所有jar中搜索该包，并获取该包下所有类\n     * @param urls URL集合\n     * @param packagePath 包路径\n     * @param childPackage 是否遍历子包\n     * @return 类的完整名称\n     */\n    private static List<String> getClassNameByJars(URL[] urls, String packagePath, boolean childPackage) {\n        List<String> myClassName = new ArrayList<String>();\n        if (urls != null) {\n            for (int i = 0; i < urls.length; i++) {\n                URL url = urls[i];\n                String urlPath = url.getPath();\n                // 不必搜索classes文件夹\n                if (urlPath.endsWith(\"classes/\")) {\n                    continue;\n                }\n                String jarPath = urlPath + \"!/\" + packagePath;\n                myClassName.addAll(getClassNameByJar(jarPath, childPackage));\n            }\n        }\n        return myClassName;\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/DefaultIndexAction.java",
    "content": "package com.xiaoleilu.loServer.action;\n\nimport com.hazelcast.core.HazelcastInstance;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.spi.IMessagesStore;\n\n/**\n * 默认的主页Action，当访问主页且没有定义主页Action时，调用此Action\n * @author Looly\n *\n */\npublic class DefaultIndexAction extends Action{\n    @Override\n    public boolean action(Request request, Response response) {\n        response.setContent(\"Welcome to LoServer.\");\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/FileAction.java",
    "content": "package com.xiaoleilu.loServer.action;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLDecoder;\nimport java.net.URLEncoder;\nimport java.nio.file.Files;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.Locale;\nimport java.util.regex.Pattern;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.io.FileUtil;\nimport cn.hutool.core.util.ReUtil;\nimport cn.hutool.core.util.StrUtil;\nimport com.hazelcast.core.HazelcastInstance;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.ServerSetting;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\n\nimport io.moquette.spi.IMessagesStore;\nimport io.netty.handler.codec.http.HttpHeaderNames;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport org.slf4j.LoggerFactory;\n\nimport static cn.hutool.core.date.DatePattern.HTTP_DATETIME_PATTERN;\n\n/**\n * 默认的主页Action，当访问主页且没有定义主页Action时，调用此Action\n * \n * @author Looly\n *\n */\npublic class FileAction extends Action {\n    private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(FileAction.class);\n\n    @Override\n    public boolean action(Request request, Response response) {\n        response.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n        if (false == Request.METHOD_GET.equalsIgnoreCase(request.getMethod())) {\n            response.sendError(HttpResponseStatus.METHOD_NOT_ALLOWED, \"Please use GET method to request file!\");\n            return true;\n        }\n\n        if(ServerSetting.isRootAvailable() == false){\n            response.sendError(HttpResponseStatus.NOT_FOUND, \"404 Root dir not avaliable!\");\n            return true;\n        }\n\n        File file = null;\n        try {\n            file = getFileByPath(request.getPath());\n        } catch (Exception e) {\n            response.sendError(HttpResponseStatus.NOT_FOUND, \"404 File not found!\");\n            return true;\n        }\n\n        // 隐藏文件或不存在，跳过\n        if (file == null || file.isHidden() || !file.exists()) {\n            response.sendError(HttpResponseStatus.NOT_FOUND, \"404 File not found!\");\n            return true;\n        }\n\n        // 非文件，跳过\n        if (!file.isFile()) {\n            response.sendError(HttpResponseStatus.FORBIDDEN, \"403 Forbidden!\");\n            return true;\n        }\n\n        Logger.debug(\"Client [{}] get file [{}]\", request.getIp(), file.getPath());\n        \n        // Cache Validation\n        String ifModifiedSince = request.getHeader(HttpHeaderNames.IF_MODIFIED_SINCE.toString());\n        if (StrUtil.isNotBlank(ifModifiedSince)) {\n            Date ifModifiedSinceDate = null;\n            try {\n                ifModifiedSinceDate = DateUtil.parse(ifModifiedSince, HTTP_DATE_FORMATER);\n            } catch (Exception e) {\n                Logger.warn(\"If-Modified-Since header parse error: {}\", e.getMessage());\n            }\n            if(ifModifiedSinceDate != null) {\n                // 只对比到秒一级别\n                long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000;\n                long fileLastModifiedSeconds = file.lastModified() / 1000;\n                if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) {\n                    Logger.debug(\"File {} not modified.\", file.getPath());\n                    response.sendNotModified();\n                    return true;\n                }\n            }\n        }\n\n        response.setContent(file);\n        if (isAudioOrVideoFile(file.getName())) {\n            response.setHeader(\"Accept-Ranges\", \"bytes\");\n        } else {\n            response.setHeader(\"Content-Disposition\", \"attachment; filename=\\\"\" + file.getName() + \"\\\"\");\n        }\n\n        return true;\n    }\n\n    private static boolean isAudioOrVideoFile(String name) {\n        try {\n            if (StringUtil.isNullOrEmpty(name)) return false;\n\n            String mimeType = Files.probeContentType(new File(name).toPath());\n            return mimeType != null && (mimeType.startsWith(\"audio/\") || mimeType.startsWith(\"video/\"));\n        } catch (IOException e) {\n            return false;\n        }\n    }\n\n    private static final Pattern INSECURE_URI = Pattern.compile(\".*[<>&\\\"].*\");\n\tprivate static final SimpleDateFormat HTTP_DATE_FORMATER = new SimpleDateFormat(HTTP_DATETIME_PATTERN, Locale.US);\n\n\t\n\t/**\n\t * 通过URL中的path获得文件的绝对路径\n\t * \n\t * @param httpPath Http请求的Path\n\t * @return 文件绝对路径\n\t */\n\tpublic static File getFileByPath(String httpPath) {\n\t\t// Decode the path.\n\t\ttry {\n\t\t\thttpPath = URLDecoder.decode(httpPath, \"UTF-8\");\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\tthrow new Error(e);\n\t\t}\n\n\t\tif (httpPath.isEmpty() || httpPath.charAt(0) != '/') {\n\t\t\treturn null;\n\t\t}\n\n\t\t// 路径安全检查\n        String path = httpPath.substring(0, httpPath.lastIndexOf(\"/\"));\n\t\tif (path.contains(\"/.\") || path.contains(\"./\") || ReUtil.isMatch(INSECURE_URI, path)) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// 转换为绝对路径\n\t\treturn FileUtil.file(ServerSetting.getRoot(), httpPath);\n\t}\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/IMAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\n\npackage com.xiaoleilu.loServer.action;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.protobuf.InvalidProtocolBufferException;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.ServerAPIHelper;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.moquette.spi.impl.Utils;\nimport io.moquette.spi.impl.security.AES;\nimport io.moquette.spi.security.Tokenor;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport cn.wildfirechat.common.ErrorCode;\n\nimport java.util.Base64;\nimport java.util.concurrent.Executor;\n\n@Route(\"/im\")\n@HttpMethod(\"POST\")\npublic class IMAction extends Action {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n\n            FullHttpRequest fullHttpRequest = (FullHttpRequest)request.getNettyRequest();\n            byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());\n\n            String str = new String(bytes);\n            try {\n                bytes = Base64.getDecoder().decode(str);\n            } catch (IllegalArgumentException e) {\n                sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null);\n                return true;\n            }\n\n            String cid = fullHttpRequest.headers().get(\"cid\");\n            byte[] cbytes = Base64.getDecoder().decode(cid);\n            cbytes = AES.AESDecrypt(cbytes, \"\", true);\n            if (cbytes == null) {\n                sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null);\n                return true;\n            }\n            cid = new String(cbytes);\n\n            MemorySessionStore.Session session = sessionsStore.getSession(cid);\n\n            if (session != null) {\n                bytes = AES.AESDecrypt(bytes, session.getSecret(), true);\n            } else {\n                sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null);\n                return true;\n            }\n\n\n            if (bytes == null) {\n                sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null);\n                return true;\n            }\n\n            try {\n                WFCMessage.IMHttpWrapper wrapper = WFCMessage.IMHttpWrapper.parseFrom(bytes);\n                String token = wrapper.getToken();\n                String userId = Tokenor.getUserId(token.getBytes());\n                if (userId == null) {\n                    sendResponse(response, ErrorCode.ERROR_CODE_TOKEN_ERROR, null);\n                } else {\n                    if(messagesStore.getUserStatus(userId) == ProtoConstants.UserStatus.Forbidden) {\n                        sendResponse(response, ErrorCode.ERROR_CODE_USER_BLOCKED, null);\n                        return true;\n                    }\n\n                    ServerAPIHelper.sendRequest(userId, wrapper.getClientId(), wrapper.getRequest(), wrapper.getData().toByteArray(), new ServerAPIHelper.Callback() {\n                        @Override\n                        public void onSuccess(byte[] result) {\n                            sendResponse(response, null, result);\n                        }\n\n                        @Override\n                        public void onError(ErrorCode errorCode) {\n                            sendResponse(response, errorCode, null);\n                        }\n\n                        @Override\n                        public void onTimeout() {\n                            sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);\n                        }\n\n                        @Override\n                        public Executor getResponseExecutor() {\n                            return command -> {\n                                ctx.executor().execute(command);\n                            };\n                        }\n                    }, ProtoConstants.RequestSourceType.Request_From_User);\n                    return false;\n                }\n            } catch (InvalidProtocolBufferException e) {\n                sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null);\n            }\n        }\n        return true;\n    }\n\n    private void sendResponse(Response response, ErrorCode errorCode, byte[] contents) {\n        response.setStatus(HttpResponseStatus.OK);\n        if(contents == null) {\n            ByteBuf ackPayload = Unpooled.buffer();\n            ackPayload.ensureWritable(1).writeByte(errorCode.getCode());\n            response.setContent(ackPayload);\n        } else {\n            response.setContent(contents);\n        }\n        response.send();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/NotFoundAction.java",
    "content": "package com.xiaoleilu.loServer.action;\n\nimport com.hazelcast.core.HazelcastInstance;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.spi.IMessagesStore;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\n\n/**\n * 错误堆栈Action类\n * @author Looly\n *\n */\npublic class NotFoundAction extends Action{\n\n    private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(NotFoundAction.class);\n\t\n\tpublic final static String ERROR_PARAM_NAME = \"_e\";\n\t\n\tprivate final static String TEMPLATE_ERROR = \"<!DOCTYPE html><html><head><title>LoServer - Error report</title><style>h1,h3 {color:white; background-color: gray;}</style></head><body><h1>HTTP Status {} - {}</h1><hr size=\\\"1\\\" noshade=\\\"noshade\\\" /><p>{}</p><hr size=\\\"1\\\" noshade=\\\"noshade\\\" /><h3>LoServer</h3></body></html>\";\n\n    @Override\n    public boolean action(Request request, Response response) {\n        response.sendError(HttpResponseStatus.NOT_FOUND, \"404 Not found!\");\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/RouteAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.protobuf.InvalidProtocolBufferException;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.moquette.persistence.ServerAPIHelper;\nimport io.moquette.spi.impl.Utils;\nimport io.moquette.spi.impl.security.AES;\nimport io.moquette.spi.security.Tokenor;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport cn.wildfirechat.common.ErrorCode;\n\nimport java.net.InetSocketAddress;\nimport java.util.Base64;\nimport java.util.Map;\nimport java.util.concurrent.Executor;\n\n@Route(\"/route\")\n@HttpMethod(\"POST\")\npublic class RouteAction extends Action {\n    private static final Logger LOG = LoggerFactory.getLogger(RouteAction.class);\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            response.setContentType(\"application/octet-stream\");\n            response.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n\n            FullHttpRequest fullHttpRequest = (FullHttpRequest) request.getNettyRequest();\n\n            byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());\n\n            String str = new String(bytes);\n            try {\n                bytes = Base64.getDecoder().decode(str);\n            } catch (IllegalArgumentException e) {\n                sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null);\n                return true;\n            }\n\n            String cid = fullHttpRequest.headers().get(\"cid\");\n            byte[] cbytes = Base64.getDecoder().decode(cid);\n            boolean[] invalidTime = new boolean[1];\n            cbytes = AES.AESDecrypt(cbytes, \"\", true, invalidTime);\n            if (cbytes == null) {\n                if(invalidTime[0]) {\n                    sendResponse(response, ErrorCode.ERROR_CODE_TIME_INCONSISTENT, null);\n                } else {\n                    sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null);\n                }\n                return true;\n            }\n            cid = new String(cbytes);\n\n            String uid = fullHttpRequest.headers().get(\"uid\");\n            byte[] ubytes = Base64.getDecoder().decode(uid);\n            ubytes = AES.AESDecrypt(ubytes, \"\", true);\n            if (ubytes == null) {\n                sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null);\n                return true;\n            }\n            uid = new String(ubytes);\n\n\n            MemorySessionStore.Session session = sessionsStore.sessionForClientAndUser(uid, cid);\n            if (session == null) {\n                ErrorCode errorCode = sessionsStore.loadActiveSession(uid, cid);\n                if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                    sendResponse(response, errorCode, null);\n                    return true;\n                }\n                session = sessionsStore.sessionForClientAndUser(uid, cid);\n            }\n\n\n            if (session != null) {\n                bytes = AES.AESDecrypt(bytes, session.getSecret(), true);\n            } else {\n                sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null);\n                return true;\n            }\n\n\n            if (bytes == null) {\n                sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null);\n                return true;\n            }\n\n            if(messagesStore.getUserStatus(uid) == ProtoConstants.UserStatus.Forbidden) {\n                sendResponse(response, ErrorCode.ERROR_CODE_USER_BLOCKED, null);\n                return true;\n            }\n\n            try {\n                WFCMessage.IMHttpWrapper wrapper = WFCMessage.IMHttpWrapper.parseFrom(bytes);\n                String token = wrapper.getToken();\n                String userId = Tokenor.getUserId(token.getBytes());\n\n                String remote = ((InetSocketAddress) ctx.channel().remoteAddress())\n                    .getAddress().getHostAddress();\n                String ip = computeRealIp(request.getHeaders(), remote);\n\n\n                LOG.info(\"RouteAction token={}, userId={}\", token, userId);\n                if (userId == null) {\n                    sendResponse(response, ErrorCode.ERROR_CODE_TOKEN_ERROR, null);\n                } else {\n                    ServerAPIHelper.sendRequest(userId, wrapper.getClientId(), wrapper.getRequest(), wrapper.getData().toByteArray(), new ServerAPIHelper.Callback() {\n                        @Override\n                        public void onSuccess(byte[] result) {\n                            sendResponse(response, null, result);\n                            //save ip after success response.\n                            sessionsStore.updateSessionIp(userId, wrapper.getClientId(), ip);\n                        }\n\n                        @Override\n                        public void onError(ErrorCode errorCode) {\n                            sendResponse(response, errorCode, null);\n                        }\n\n                        @Override\n                        public void onTimeout() {\n                            sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);\n                        }\n\n                        @Override\n                        public Executor getResponseExecutor() {\n                            return command -> {\n                                ctx.executor().execute(command);\n                            };\n                        }\n                    }, ProtoConstants.RequestSourceType.Request_From_User);\n                    return false;\n                }\n            } catch (InvalidProtocolBufferException e) {\n                sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null);\n            }\n        }\n        return true;\n    }\n\n    private String computeRealIp(Map<String, String> h, String remote) {\n        String xff = h.get(\"X-Forwarded-For\");\n        if (xff != null && !xff.isEmpty() && !\"unknown\".equalsIgnoreCase(xff)) {\n            int idx = xff.indexOf(',');\n            String first = (idx > 0 ? xff.substring(0, idx) : xff).trim();\n            return first;\n        }\n        String xri = h.get(\"X-Real-IP\");\n        if (xri != null && !xri.isEmpty() && !\"unknown\".equalsIgnoreCase(xri)) {\n            return xri;\n        }\n        return remote;\n    }\n\n    private void sendResponse(Response response, ErrorCode errorCode, byte[] contents) {\n        response.setStatus(HttpResponseStatus.OK);\n        if (contents == null) {\n            ByteBuf ackPayload = Unpooled.buffer();\n            ackPayload.ensureWritable(1).writeByte(errorCode.getCode());\n            contents = ackPayload.array();\n        }\n\n        response.setContent(contents);\n        response.send();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/UnknownErrorAction.java",
    "content": "package com.xiaoleilu.loServer.action;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\n\nimport com.hazelcast.core.HazelcastInstance;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\n\nimport io.moquette.spi.IMessagesStore;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 错误堆栈Action类\n * @author Looly\n *\n */\npublic class UnknownErrorAction extends Action{\n    private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(UnknownErrorAction.class);\n\t\n\tpublic final static String ERROR_PARAM_NAME = \"_e\";\n\t\n\tprivate final static String TEMPLATE_ERROR = \"<!DOCTYPE html><html><head><title>LoServer - Error report</title><style>h1,h3 {color:white; background-color: gray;}</style></head><body><h1>HTTP Status {} - {}</h1><hr size=\\\"1\\\" noshade=\\\"noshade\\\" /><p>{}</p><hr size=\\\"1\\\" noshade=\\\"noshade\\\" /><h3>LoServer</h3></body></html>\";\n\n    @Override\n    public boolean action(Request request, Response response) {\n        response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/UploadFileAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action;\n\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.RequireAuthentication;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.*;\nimport io.moquette.server.config.MediaServerConfig;\nimport io.moquette.spi.impl.security.AES;\nimport io.moquette.spi.security.DES;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.handler.codec.http.*;\nimport io.netty.handler.codec.http.multipart.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.io.RandomAccessFile;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.UUID;\n\nimport static com.xiaoleilu.loServer.handler.HttpResponseHelper.getFileExt;\n\n@Route(\"/fs\")\n@HttpMethod(\"POST\")\n@RequireAuthentication\npublic class UploadFileAction extends Action {\n    private static final String KEY = \"imfile\";\n    private static final Logger logger = LoggerFactory.getLogger(UploadFileAction.class);\n    private static final HttpDataFactory factory = new DefaultHttpDataFactory(false);\n\n    public static class InvalidateTokenExecption extends Exception {\n\n    }\n\n    public static String getToken(int type) {\n        String signKey = KEY + \"|\" + (System.currentTimeMillis()) + \"|\" + type;\n        try {\n            return DES.encryptDES(signKey);\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public static int validateToken(String token) throws InvalidateTokenExecption {\n        try {\n            String signKey = DES.decryptDES(token);\n            String[] parts = signKey.split(\"\\\\|\");\n            if(parts.length == 3) {\n                if(parts[0].equals(KEY)) {\n                    long timestamp = Long.parseLong(parts[1]);\n                    if(Math.abs(System.currentTimeMillis() - timestamp) < 2 * 60 * 60 * 1000) {\n                        return Integer.parseInt(parts[2]);\n                    }\n                }\n            }\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            //e.printStackTrace();\n        }\n        throw new InvalidateTokenExecption();\n    }\n\n    @Override\n    public boolean action(Request r, Response response) {\n        if (r.getNettyRequest() instanceof FullHttpRequest) {\n\n            FullHttpRequest request = (FullHttpRequest) r.getNettyRequest();\n            String requestId = UUID.randomUUID().toString().replace(\"-\", \"\");\n            logger.info(\"HttpFileServerHandler received a request: method=\" + request.getMethod() + \", uri=\" + request.getUri() + \", requestId=\" + requestId);\n\n            if (!request.getDecoderResult().isSuccess()) {\n                logger.warn(\"http decode failed!\");\n                response.setStatus(HttpResponseStatus.BAD_REQUEST);\n                response.setContent(\"http decode failed\");\n                return true;\n            }\n\n            multipartUpload(request, requestId, response);\n\n        }\n        return true;\n    }\n\n\n    /**\n     * multipart上传\n     */\n    private void multipartUpload(FullHttpRequest request, String requestId, Response response) {\n        HttpPostRequestDecoder decoder = null;\n        try {\n            decoder = new HttpPostRequestDecoder(factory, request);\n        } catch (HttpPostRequestDecoder.ErrorDataDecoderException e1) {\n            logger.error(\"Failed to decode file data!\", e1);\n            response.setStatus(HttpResponseStatus.BAD_REQUEST);\n            response.setContent(\"Failed to decode file data!\");\n            return;\n        }\n\n\n        if (decoder != null) {\n            if (request instanceof HttpContent) {\n                HttpContent chunk = (HttpContent) request;\n                try {\n                    decoder.offer(chunk);\n                } catch (HttpPostRequestDecoder.ErrorDataDecoderException e1) {\n                    logger.warn(\"BAD_REQUEST, Failed to decode file data\");\n                    response.setStatus(HttpResponseStatus.BAD_REQUEST);\n                    response.setContent(\"Failed to decode file data!\");\n                    return;\n                }\n\n                long fileTotalSize = 0;\n                if (request.headers().contains(\"X-File-Total-Size\")) {\n                    try {\n                        fileTotalSize = Integer.parseInt(request.headers().get(\"X-File-Total-Size\"));\n                    } catch (Exception e) {\n                        logger.warn(\"invalid X-File-Total-Size value!\");\n                    }\n                }\n\n                readHttpDataChunkByChunk(response, decoder, requestId, HttpHeaders.isKeepAlive(request));\n                decoder.destroy();\n                \n                if (chunk instanceof LastHttpContent) {\n\n                }\n            } else {\n                logger.warn(\"BAD_REQUEST, Not a http request\");\n                response.setStatus(HttpResponseStatus.BAD_REQUEST);\n                response.setContent(\"Not a http request\");\n            }\n        }\n    }\n\n    /**\n     * readHttpDataChunkByChunk\n     */\n    private void readHttpDataChunkByChunk(Response response, HttpPostRequestDecoder decoder, String requestId, boolean isKeepAlive) {\n        try {\n            int[] bucket = new int[1];\n            bucket[0] = -1;\n            while (decoder.hasNext()) {\n                InterfaceHttpData data = decoder.next();\n                if (data != null) {\n                    try {\n                        if(!writeFileUploadData(data, response, requestId, isKeepAlive, bucket)) {\n                            break;\n                        }\n                    } finally {\n                        data.release();\n                    }\n                }\n            }\n        } catch (Exception e) {\n            logger.info(\"chunk end\");\n        }\n    }\n\n    /**\n     * writeFileUploadData\n     */\n    private boolean writeFileUploadData(InterfaceHttpData data, Response response, String requestId, boolean isKeepAlive, int[] bucket) {\n        try {\n            if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {\n                FileUpload fileUpload = (FileUpload) data;\n\n                String remoteFileName = fileUpload.getFilename();\n                long remoteFileSize = fileUpload.length();\n\n                if(bucket[0] == -1) {\n                    logger.warn(\"Not authenticated!\");\n\n                    response.setStatus(HttpResponseStatus.BAD_REQUEST);\n                    response.setContent(\"Not authenticated!\");\n                    return false;\n                }\n\n                if(remoteFileName != null && remoteFileName.length() > 2 && remoteFileName.startsWith(\"'\") && remoteFileName.endsWith(\"'\")) {\n                    remoteFileName = remoteFileName.substring(1, remoteFileName.length()-1);\n                }\n\n                if (StringUtil.isNullOrEmpty(remoteFileName)) {\n                    logger.warn(\"remoteFileName is empty!\");\n\n                    response.setStatus(HttpResponseStatus.BAD_REQUEST);\n                    response.setContent(\"file name is empty\");\n                    return false;\n                }\n\n                if (StringUtil.isNullOrEmpty(requestId)) {\n                    logger.warn(\"requestId is empty!\");\n                    response.setStatus(HttpResponseStatus.BAD_REQUEST);\n                    response.setContent(\"requestId is empty!\");\n                    return false;\n                }\n\n                if (remoteFileSize > 200 * 1024 * 1024) {\n                    logger.warn(\"file over limite!(\" + remoteFileSize + \")\");\n                    response.setStatus(HttpResponseStatus.BAD_REQUEST);\n                    response.setContent(\"file over limite!\");\n                    return false;\n                }\n\n                remoteFileName = getSafeFileName(remoteFileName);\n\n                String remoteFileExt = \"\";\n                if (remoteFileName.lastIndexOf(\".\") == -1) {\n                    remoteFileExt = \"octetstream\";\n                    remoteFileName = remoteFileName + \".\" + remoteFileExt;\n\n                } else {\n                    remoteFileExt = getFileExt(remoteFileName);\n                }\n\n                if (StringUtil.isNullOrEmpty(remoteFileExt) || remoteFileExt.equals(\"ing\")) {\n                    logger.warn(\"Invalid file extention name\");\n                    response.setStatus(HttpResponseStatus.BAD_REQUEST);\n                    response.setContent(\"Invalid file extention name\");\n                    return false;\n                }\n\n                int remoteFileTotalSize = (int) remoteFileSize;\n\n\n                ByteBuf byteBuf = null;\n                int savedThunkSize = 0; // 分片接收保存的大小\n                int offset = 0; // 断点续传开始位置\n\n                Date nowTime=new Date();\n                SimpleDateFormat time=new SimpleDateFormat(\"yyyy/MM/dd/HH/mm/ss\");\n                String datePath = time.format(nowTime);\n\n                datePath = \"fs/\" + bucket[0] + \"/\" + datePath; //add bucket\n\n                String dir;\n                if(MediaServerConfig.FILE_STROAGE_ROOT.startsWith(\"/\") || MediaServerConfig.FILE_STROAGE_ROOT.startsWith(\"~/\") || MediaServerConfig.FILE_STROAGE_ROOT.startsWith(\"./\")) {\n                    dir = MediaServerConfig.FILE_STROAGE_ROOT + \"/\" + datePath;\n                } else {\n                    dir = \"./\" + MediaServerConfig.FILE_STROAGE_ROOT + \"/\" + datePath;\n                }\n\n                File dirFile = new File(dir);\n                boolean bFile  = dirFile.exists();\n\n                if(!bFile) {\n                    bFile = dirFile.mkdirs();\n                    if (!bFile) {\n                        logger.error(\"create dirs error! {}\", dir);\n                        response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);\n                        response.setContent(\"服务器错误：无法创建文件\");\n                        return false;\n                    }\n                }\n\n\n                String filePath = dir + \"/\" + (StringUtil.isNullOrEmpty(remoteFileName) ? requestId : remoteFileName);\n                logger.info(\"the file path is \" + filePath);\n\n                File tmpFile = new File(filePath);\n\n                logger.info(\"before write the file\");\n                boolean isError = false;\n                while (true) {\n                    byte[] thunkData;\n                    try {\n                        byteBuf = fileUpload.getChunk(128 * 1024);\n                        int readableBytesSize = byteBuf.readableBytes();\n                        thunkData = new byte[readableBytesSize];\n                        byteBuf.readBytes(thunkData);\n\n                        put(tmpFile, offset, thunkData);\n\n                        savedThunkSize += readableBytesSize;\n                        offset += readableBytesSize;\n                        byteBuf.release();\n                        byteBuf = null;\n\n                        if (savedThunkSize >= remoteFileSize) {\n                            fileUpload.release();\n\n                            response.setStatus(HttpResponseStatus.OK);\n                            String relativePath = datePath + \"/\" +  (StringUtil.isNullOrEmpty(remoteFileName) ? requestId : remoteFileName);\n                            response.setContent(\"{\\\"key\\\":\\\"\" + relativePath + \"\\\"}\");\n                            break;\n                        }\n                    } catch (Exception e) {\n                        logger.error(\"save thunckData error!\", e);\n                        if (fileUpload != null)\n                            fileUpload.release();\n\n                        if (byteBuf != null)\n                            byteBuf.release();\n\n                        response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);\n                        response.setContent(\"服务器错误：\" + e.getMessage());\n                        isError = true;\n\n                        return false;\n                    } finally {\n                        thunkData = null;\n                        if (isError) {\n                            tmpFile.delete();\n                        }\n                    }\n                }\n            } else if(data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {\n                Attribute attribute = (Attribute)data;\n                if(attribute.getName().equals(\"token\")) {\n                    String token = attribute.getValue();\n\n                    try {\n                        bucket[0] = validateToken(token);\n                    } catch (InvalidateTokenExecption e) {\n                        logger.error(\"无效的token!\", e);\n                        response.setStatus(HttpResponseStatus.BAD_REQUEST);\n                        response.setContent(\"无效的token：\" + e.getMessage());\n                        return false;\n                    }\n                }\n            }\n        } catch (Exception e) {\n            logger.error(\"writeHttpData error!\", e);\n            response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);\n            response.setContent(\"服务器错误：\" + e.getMessage());\n            return false;\n        }\n        return true;\n    }\n\n    private static String getSafeFileName(String originalFilename) {\n        // Paths.get() 会解析路径，getFileName() 只取最后一部分（纯文件名）\n        Path filenamePath = Paths.get(originalFilename.trim());\n        String safeFilename = filenamePath.getFileName().toString();\n        // 额外过滤特殊字符（可选，根据业务需要）\n        safeFilename = safeFilename.replaceAll(\"[\\\\\\\\/:*?\\\"<>|]\", \"_\");\n        return safeFilename.isEmpty() ? \"default_file_\" + System.currentTimeMillis() : safeFilename;\n    }\n\n    public static void put(File file, long pos, byte[] data) throws Exception {\n        RandomAccessFile raf = null;\n        try {\n            raf = new RandomAccessFile(file, \"rwd\");\n            raf.seek(pos);\n            raf.write(data);\n        } finally {\n            try {\n                if (raf != null)\n                    raf.close();\n            } catch (Exception e) {\n                logger.warn(\"release error!\", e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/VersionAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action;\n\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.InputUserLogin;\nimport cn.wildfirechat.pojos.OutputLoginData;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.GitRepositoryState;\nimport win.liyufan.im.Utility;\n\nimport java.io.IOException;\n\n@Route(\"/api/version\")\n@HttpMethod(\"GET\")\npublic class VersionAction extends Action {\n\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            if(closeApiVersion) {\n                response.sendError(HttpResponseStatus.NOT_FOUND, \"404 Not found!\");\n                return true;\n            }\n\n            response.setStatus(HttpResponseStatus.OK);\n            try {\n\n                response.setContent(Utility.formatJson(gson.toJson(GitRepositoryState.getGitRepositoryState())));\n            } catch (IOException e) {\n                e.printStackTrace();\n                response.setContent(\"{\\\"version\\\":\\\"unknown\\\"}\");\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/AddFriendRequestAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputAddFriendRequest;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Friend_Send_Request)\n@HttpMethod(\"POST\")\npublic class AddFriendRequestAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputAddFriendRequest input = getRequestBody(request.getNettyRequest(), InputAddFriendRequest.class);\n\n            if (StringUtil.isNullOrEmpty(input.getUserId()) || StringUtil.isNullOrEmpty(input.getFriendUid())) {\n                sendResponse(response, ErrorCode.INVALID_PARAMETER, null);\n                return true;\n            }\n\n            WFCMessage.AddFriendRequest addFriendRequest = WFCMessage.AddFriendRequest.newBuilder().setReason(input.getReason()).setTargetUid(input.getFriendUid()).build();\n            sendApiMessage(response, input.getUserId(), IMTopic.AddFriendRequestTopic, addFriendRequest.toByteArray(), result -> {\n                ByteBuf byteBuf = Unpooled.buffer();\n                byteBuf.writeBytes(result);\n                ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                return new Result(errorCode);\n            }, !input.isForce());\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/AddGroupMemberAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport cn.wildfirechat.pojos.InputAddGroupMember;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Group_Member_Add)\n@HttpMethod(\"POST\")\npublic class AddGroupMemberAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputAddGroupMember inputAddGroupMember = getRequestBody(request.getNettyRequest(), InputAddGroupMember.class);\n            if (inputAddGroupMember.isValide()) {\n                sendApiMessage(response, inputAddGroupMember.getOperator(), IMTopic.AddGroupMemberTopic, inputAddGroupMember.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/AdminAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.action.Action;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.ServerAPIHelper;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport cn.wildfirechat.common.ErrorCode;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.RateLimiter;\nimport win.liyufan.im.Utility;\n\nimport java.util.concurrent.Executor;\n\nabstract public class AdminAction extends Action {\n    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(AdminAction.class);\n    private static String SECRET_KEY = \"123456\";\n    private static boolean NO_CHECK_TIME = false;\n    public static void setSecretKey(String secretKey) {\n        SECRET_KEY = secretKey;\n    }\n\n    public static String getSecretKey() {\n        return SECRET_KEY;\n    }\n\n    public static void setNoCheckTime(String noCheckTime) {\n        try {\n            NO_CHECK_TIME = Boolean.parseBoolean(noCheckTime);\n        } catch (Exception e) {\n\n        }\n    }\n\n    @Override\n    public ErrorCode preAction(Request request, Response response) {\n        if (!adminLimiter.isGranted(\"admin\")) {\n            return ErrorCode.ERROR_CODE_OVER_FREQUENCY;\n        }\n\n        if(APIPath.Health.equals(request.getUri())) {\n            return ErrorCode.ERROR_CODE_SUCCESS;\n        }\n\n        String nonce = request.getHeader(\"nonce\");\n        if (StringUtil.isNullOrEmpty(nonce)) {\n            nonce = request.getHeader(\"Nonce\");\n        }\n        String timestamp = request.getHeader(\"timestamp\");\n        if (StringUtil.isNullOrEmpty(timestamp)) {\n            timestamp = request.getHeader(\"Timestamp\");\n        }\n        String sign = request.getHeader(\"sign\");\n        if (StringUtil.isNullOrEmpty(sign)) {\n            sign = request.getHeader(\"Sign\");\n        }\n        \n        if (StringUtil.isNullOrEmpty(nonce) || StringUtil.isNullOrEmpty(timestamp) || StringUtil.isNullOrEmpty(sign)) {\n            return ErrorCode.ERROR_CODE_API_NOT_SIGNED;\n        }\n\n        Long ts;\n        try {\n            ts = Long.parseLong(timestamp);\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            return ErrorCode.ERROR_CODE_API_NOT_SIGNED;\n        }\n\n        if (!NO_CHECK_TIME && System.currentTimeMillis() - ts > 2 * 60 * 60 * 1000) {\n            return ErrorCode.ERROR_CODE_SIGN_EXPIRED;\n        }\n\n        String str = nonce + \"|\" + SECRET_KEY + \"|\" + timestamp;\n        String localSign = DigestUtils.sha1Hex(str);\n        return localSign.equals(sign) ? ErrorCode.ERROR_CODE_SUCCESS : ErrorCode.ERROR_CODE_AUTH_FAILURE;\n    }\n\n    protected void sendResponse(Response response, ErrorCode errorCode, Object data) {\n        if(response != null) {\n            response.setStatus(HttpResponseStatus.OK);\n            if (errorCode == null) {\n                errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n            }\n\n            RestResult result = RestResult.resultOf(errorCode, errorCode.getMsg(), data);\n            response.setContent(gson.toJson(result));\n            response.send();\n        }\n    }\n    protected void sendApiMessage(Response response, String fromUser, String topic, byte[] message, ApiCallback callback) {\n        sendApiMessage(response, fromUser, null, topic, message, callback, false);\n    }\n\n    protected void sendApiMessage(Response response, String fromUser, String topic, byte[] message, ApiCallback callback, boolean noAdmin) {\n        sendApiMessage(response, fromUser, null, topic, message, callback, noAdmin);\n    }\n\n    protected void sendApiMessage(Response response, String fromUser, String clientId, String topic, byte[] message, ApiCallback callback, boolean noAdmin) {\n        ServerAPIHelper.sendRequest(fromUser, clientId, topic, message, callback == null ? null : new ServerAPIHelper.Callback() {\n            @Override\n            public void onSuccess(byte[] result) {\n                if(callback != null) {\n                    Result r = callback.onResult(result);\n                    sendResponse(response, r.getErrorCode(), r.getData());\n                }\n            }\n\n            @Override\n            public void onError(ErrorCode errorCode) {\n                sendResponse(response, errorCode, null);\n            }\n\n            @Override\n            public void onTimeout() {\n                sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);\n            }\n\n            @Override\n            public Executor getResponseExecutor() {\n                return command -> {\n                    ctx.executor().execute(command);\n                };\n            }\n        }, noAdmin ? ProtoConstants.RequestSourceType.Request_From_User : ProtoConstants.RequestSourceType.Request_From_Admin);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/AliasGetAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetAlias;\nimport cn.wildfirechat.pojos.InputGetFriendList;\nimport cn.wildfirechat.pojos.OutputGetAlias;\nimport cn.wildfirechat.pojos.OutputStringList;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport com.xiaoleilu.loServer.model.FriendData;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Route(APIPath.Friend_Get_Alias)\n@HttpMethod(\"POST\")\npublic class AliasGetAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetAlias input = getRequestBody(request.getNettyRequest(), InputGetAlias.class);\n            List<FriendData> dataList = messagesStore.getFriendList(input.getOperator(), null, 0);\n            List<String> list = new ArrayList<>();\n            OutputGetAlias out = new OutputGetAlias(input.getOperator(), input.getTargetId());\n\n            for (FriendData data : dataList) {\n                if (data.getFriendUid().equals(input.getTargetId())) {\n                    out.setAlias(data.getAlias());\n                    break;\n                }\n            }\n\n            setResponseContent(RestResult.ok(out), response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/AliasPutAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetFriendList;\nimport cn.wildfirechat.pojos.InputUpdateAlias;\nimport cn.wildfirechat.pojos.OutputCreateChannel;\nimport cn.wildfirechat.pojos.OutputStringList;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport com.xiaoleilu.loServer.model.FriendData;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Route(APIPath.Friend_Set_Alias)\n@HttpMethod(\"POST\")\npublic class AliasPutAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputUpdateAlias input = getRequestBody(request.getNettyRequest(), InputUpdateAlias.class);\n            if(!StringUtil.isNullOrEmpty(input.getOperator()) && !StringUtil.isNullOrEmpty(input.getTargetId())) {\n                WFCMessage.AddFriendRequest addFriendRequest = WFCMessage.AddFriendRequest.newBuilder().setTargetUid(input.getTargetId()).setReason(input.getAlias()==null?\"\":input.getAlias()).build();\n                sendApiMessage(response, input.getOperator(), IMTopic.SetFriendAliasTopic, addFriendRequest.toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                ErrorCode errorCode = messagesStore.setFriendAliasRequest(input.getOperator(), input.getTargetId(), input.getAlias(), new long[1]);\n                setResponseContent(RestResult.resultOf(errorCode), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/ApplicationGetUserInfoAction.java",
    "content": "package com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputApplicationGetUserInfo;\nimport cn.wildfirechat.pojos.OutputApplicationUserInfo;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\n\n@Route(APIPath.User_Application_Get_UserInfo)\n@HttpMethod(\"POST\")\npublic class ApplicationGetUserInfoAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputApplicationGetUserInfo inputUserToken = getRequestBody(request.getNettyRequest(), InputApplicationGetUserInfo.class);\n\n            RestResult result;\n            if (inputUserToken == null || StringUtil.isNullOrEmpty(inputUserToken.getAuthCode())) {\n                result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);\n            } else {\n                String userId = messagesStore.verifyApplicationAuthCode(inputUserToken.getAuthCode(), \"admin\", ProtoConstants.ApplicationType.ApplicationType_Admin);\n                if(userId != null) {\n                    OutputApplicationUserInfo outputVerifyApplicationUser = new OutputApplicationUserInfo();\n                    outputVerifyApplicationUser.setUserId(userId);\n                    WFCMessage.User user = messagesStore.getUserInfo(userId);\n                    if(user != null) {\n                        outputVerifyApplicationUser.setDisplayName(user.getDisplayName());\n                        outputVerifyApplicationUser.setPortraitUrl(user.getPortrait());\n                    }\n                    result = RestResult.ok(outputVerifyApplicationUser);\n                } else {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_TOKEN_ERROR);\n                }\n            }\n\n            response.setStatus(HttpResponseStatus.OK);\n            response.setContent(gson.toJson(result));\n        }\n        return true;\n    }\n}\n\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/BlacklistAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputBlacklistRequest;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Blacklist_Update_Status)\n@HttpMethod(\"POST\")\npublic class BlacklistAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputBlacklistRequest inputData = getRequestBody(request.getNettyRequest(), InputBlacklistRequest.class);\n            if (inputData != null\n                && !StringUtil.isNullOrEmpty(inputData.getUserId())\n                && !StringUtil.isNullOrEmpty(inputData.getTargetUid())\n            ) {\n                WFCMessage.BlackUserRequest friendRequest = WFCMessage.BlackUserRequest.newBuilder().setUid(inputData.getTargetUid()).setStatus(inputData.getStatus()).build();\n                sendApiMessage(response, inputData.getUserId(), IMTopic.BlackListUserTopic, friendRequest.toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/BlacklistGetAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.InputGetFriendList;\nimport cn.wildfirechat.pojos.InputUserId;\nimport cn.wildfirechat.pojos.OutputStringList;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport com.xiaoleilu.loServer.model.FriendData;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Route(APIPath.Blacklist_Get_List)\n@HttpMethod(\"POST\")\npublic class BlacklistGetAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputUserId inputGetFriendList = getRequestBody(request.getNettyRequest(), InputUserId.class);\n            List<FriendData> dataList = messagesStore.getFriendList(inputGetFriendList.getUserId(), null, 0);\n            List<String> list = new ArrayList<>();\n            for (FriendData data : dataList) {\n                if (data.getBlacked() > 0) {\n                    list.add(data.getFriendUid());\n                }\n            }\n            setResponseContent(RestResult.ok(new OutputStringList(list)), response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/BlockUserAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport cn.wildfirechat.pojos.InputOutputUserBlockStatus;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.ServerAPIHelper;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport cn.wildfirechat.common.ErrorCode;\n\n@Route(APIPath.User_Update_Block_Status)\n@HttpMethod(\"POST\")\npublic class BlockUserAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputOutputUserBlockStatus inputUserBlock = getRequestBody(request.getNettyRequest(), InputOutputUserBlockStatus.class);\n            if (inputUserBlock != null\n                && !StringUtil.isNullOrEmpty(inputUserBlock.getUserId())) {\n\n                ErrorCode errorCode = messagesStore.modifyUserStatus(inputUserBlock.getUserId(), inputUserBlock.getStatus());\n                response.setStatus(HttpResponseStatus.OK);\n                RestResult result;\n                result = RestResult.resultOf(errorCode);\n                response.setContent(gson.toJson(result));\n\n                if (inputUserBlock.getStatus() == 2) {\n                    sendApiMessage(null, null, ServerAPIHelper.KICKOFF_USER_REQUEST, inputUserBlock.getUserId().getBytes(), null);\n                }\n\n                sendResponse(response, ErrorCode.ERROR_CODE_SUCCESS, null);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/BroadcastMessageAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.BroadMessageData;\nimport cn.wildfirechat.pojos.BroadMessageResult;\nimport com.google.gson.Gson;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Msg_Broadcast)\n@HttpMethod(\"POST\")\npublic class BroadcastMessageAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            BroadMessageData sendMessageData = getRequestBody(request.getNettyRequest(), BroadMessageData.class);\n            if (BroadMessageData.isValide(sendMessageData) && !StringUtil.isNullOrEmpty(sendMessageData.getSender())) {\n                sendApiMessage(response, sendMessageData.getSender(), IMTopic.BroadcastMessageTopic, sendMessageData.toProtoMessage().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        long messageId = byteBuf.readLong();\n                        long count = byteBuf.readLong();\n                        return new Result(errorCode, new BroadMessageResult(messageId, count));\n                    } else {\n                        return new Result(errorCode);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/ChannelSubscriberAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputChannelSubscribe;\nimport cn.wildfirechat.pojos.InputCreateChannel;\nimport cn.wildfirechat.pojos.InputSubscribeChannel;\nimport cn.wildfirechat.pojos.OutputCreateChannel;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.action.channel.ChannelAction;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Subscribe_Channel)\n@HttpMethod(\"POST\")\npublic class ChannelSubscriberAction extends AdminAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputSubscribeChannel inputSubscribeChannel = getRequestBody(request.getNettyRequest(), InputSubscribeChannel.class);\n            if (inputSubscribeChannel != null\n                && !io.netty.util.internal.StringUtil.isNullOrEmpty(inputSubscribeChannel.getChannelId())\n                && !io.netty.util.internal.StringUtil.isNullOrEmpty(inputSubscribeChannel.getUserId())) {\n\n                WFCMessage.ListenChannel.Builder builder = WFCMessage.ListenChannel.newBuilder().setChannelId(inputSubscribeChannel.getChannelId()).setListen(inputSubscribeChannel.getSubscribe());\n                sendApiMessage(response, inputSubscribeChannel.getUserId(), IMTopic.ChannelListenTopic, builder.build().toByteArray(), result -> {\n                    ErrorCode errorCode = ErrorCode.fromCode(result[0]);\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        return new Result(ErrorCode.ERROR_CODE_SUCCESS);\n                    } else {\n                        return new Result(errorCode);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/CheckUserOnlineAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.OutputCheckUserOnline;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.ServerAPIHelper;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\nimport cn.wildfirechat.common.ErrorCode;\n\n@Route(APIPath.User_Get_Online_Status)\n@HttpMethod(\"POST\")\npublic class CheckUserOnlineAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return false;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetUserInfo inputUserId = getRequestBody(request.getNettyRequest(), InputGetUserInfo.class);\n            if (inputUserId == null || !StringUtil.isNullOrEmpty(inputUserId.getUserId())) {\n                sendApiMessage(response, inputUserId.getUserId(), ServerAPIHelper.CHECK_USER_ONLINE_REQUEST, inputUserId.getUserId().getBytes(), res -> {\n                    OutputCheckUserOnline out = gson.fromJson(new String(res), OutputCheckUserOnline.class);\n                    return new Result(ErrorCode.ERROR_CODE_SUCCESS, out);\n                });\n                return false;\n            } else {\n                sendResponse(response, ErrorCode.INVALID_PARAMETER, null);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/CheckUserSubscribeChannelAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputChannelId;\nimport cn.wildfirechat.pojos.InputSubscribeChannel;\nimport cn.wildfirechat.pojos.OutputBooleanValue;\nimport cn.wildfirechat.pojos.OutputGetChannelInfo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Check_User_Subscribe_Channel)\n@HttpMethod(\"POST\")\npublic class CheckUserSubscribeChannelAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputSubscribeChannel inputSubscribeChannel = getRequestBody(request.getNettyRequest(), InputSubscribeChannel.class);\n            if (inputSubscribeChannel != null\n                && !StringUtil.isNullOrEmpty(inputSubscribeChannel.getChannelId())\n                && !StringUtil.isNullOrEmpty(inputSubscribeChannel.getUserId())) {\n                boolean isInChannel = messagesStore.checkUserInChannel(inputSubscribeChannel.getUserId(), inputSubscribeChannel.getChannelId());\n                OutputBooleanValue outputBooleanValue = new OutputBooleanValue();\n                outputBooleanValue.value = isInChannel;\n                setResponseContent(RestResult.ok(outputBooleanValue), response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/CreateChannelAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.*;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Create_Channel)\n@HttpMethod(\"POST\")\npublic class CreateChannelAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputCreateChannel inputCreateChannel = getRequestBody(request.getNettyRequest(), InputCreateChannel.class);\n            if (inputCreateChannel != null\n                && !StringUtil.isNullOrEmpty(inputCreateChannel.getName())\n                && !StringUtil.isNullOrEmpty(inputCreateChannel.getOwner())) {\n\n\n                if(StringUtil.isNullOrEmpty(inputCreateChannel.getTargetId())) {\n                    inputCreateChannel.setTargetId(messagesStore.getShortUUID());\n                }\n\n                sendApiMessage(response, inputCreateChannel.getOwner(), IMTopic.CreateChannelTopic, inputCreateChannel.toProtoChannelInfo().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        byte[] data = new byte[byteBuf.readableBytes()];\n                        byteBuf.readBytes(data);\n                        String str = new String(data);\n                        String[] ss = str.split(\"\\\\|\");\n                        String channelId = ss[0];\n                        String secret = ss[1];\n                        return new Result(ErrorCode.ERROR_CODE_SUCCESS, new OutputCreateChannel(channelId, secret));\n                    } else {\n                        return new Result(errorCode);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/CreateChatroomAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.InputCreateChatroom;\nimport cn.wildfirechat.pojos.OutputCreateChatroom;\nimport io.moquette.spi.impl.Utils;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport cn.wildfirechat.common.ErrorCode;\n\n@Route(APIPath.Create_Chatroom)\n@HttpMethod(\"POST\")\npublic class CreateChatroomAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            FullHttpRequest fullHttpRequest = (FullHttpRequest)request.getNettyRequest();\n            byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());\n            String content = new String(bytes);\n            \n            InputCreateChatroom inputCreateChatroom = gson.fromJson(content, InputCreateChatroom.class);\n            if (inputCreateChatroom != null\n                && !StringUtil.isNullOrEmpty(inputCreateChatroom.getTitle())) {\n\n                if (StringUtil.isNullOrEmpty(inputCreateChatroom.getChatroomId())) {\n                    inputCreateChatroom.setChatroomId(messagesStore.getShortUUID());\n                }\n\n                WFCMessage.ChatroomInfo info = inputCreateChatroom.toChatroomInfo();\n                messagesStore.createChatroom(inputCreateChatroom.getChatroomId(), info);\n                setResponseContent(RestResult.ok(new OutputCreateChatroom(inputCreateChatroom.getChatroomId())), response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/CreateGroupAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport cn.wildfirechat.pojos.InputCreateGroup;\nimport cn.wildfirechat.pojos.OutputCreateGroupResult;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Create_Group)\n@HttpMethod(\"POST\")\npublic class CreateGroupAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputCreateGroup inputCreateGroup = getRequestBody(request.getNettyRequest(), InputCreateGroup.class);\n            if (inputCreateGroup.isValide()) {\n                sendApiMessage(response, inputCreateGroup.getOperator(), IMTopic.CreateGroupTopic, inputCreateGroup.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        byte[] data = new byte[byteBuf.readableBytes()];\n                        byteBuf.readBytes(data);\n                        String groupId = new String(data);\n                        return new Result(ErrorCode.ERROR_CODE_SUCCESS, new OutputCreateGroupResult(groupId));\n                    } else {\n                        return new Result(errorCode);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/CreateRobotAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.IMExceptionEvent;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.InputCreateRobot;\nimport cn.wildfirechat.pojos.OutputCreateRobot;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport cn.wildfirechat.common.ErrorCode;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.UUIDGenerator;\nimport win.liyufan.im.Utility;\n\n@Route(APIPath.Create_Robot)\n@HttpMethod(\"POST\")\npublic class CreateRobotAction extends AdminAction {\n    private static final Logger LOG = LoggerFactory.getLogger(CreateRobotAction.class);\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputCreateRobot inputCreateRobot = getRequestBody(request.getNettyRequest(), InputCreateRobot.class);\n            if (inputCreateRobot != null\n                && !StringUtil.isNullOrEmpty(inputCreateRobot.getName())) {\n\n                if(StringUtil.isNullOrEmpty(inputCreateRobot.getUserId())) {\n                    inputCreateRobot.setUserId(messagesStore.getShortUUID());\n                }\n\n                WFCMessage.User newUser = inputCreateRobot.toUser();\n                try {\n                    messagesStore.addUserInfo(newUser);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, IMExceptionEvent.EventType.ADMIN_API_Exception);\n                    response.setStatus(HttpResponseStatus.OK);\n                    RestResult result = RestResult.resultOf(ErrorCode.ERROR_CODE_SERVER_ERROR, e.getMessage());\n                    response.setContent(gson.toJson(result));\n                    return true;\n                }\n\n                if (StringUtil.isNullOrEmpty(inputCreateRobot.getOwner())) {\n                    inputCreateRobot.setOwner(inputCreateRobot.getUserId());\n                }\n\n                if (StringUtil.isNullOrEmpty(inputCreateRobot.getSecret())) {\n                    inputCreateRobot.setSecret(UUIDGenerator.getUUID());\n                }\n                messagesStore.addRobot(inputCreateRobot.toRobot());\n                setResponseContent(RestResult.ok(new OutputCreateRobot(inputCreateRobot.getUserId(), inputCreateRobot.getSecret())), response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/CreateUserAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.IMExceptionEvent;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.OutputCreateUser;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport cn.wildfirechat.common.ErrorCode;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.UUIDGenerator;\nimport win.liyufan.im.Utility;\n\n@Route(APIPath.Create_User)\n@HttpMethod(\"POST\")\npublic class CreateUserAction extends AdminAction {\n    private static final Logger LOG = LoggerFactory.getLogger(CreateUserAction.class);\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputOutputUserInfo inputCreateUser = getRequestBody(request.getNettyRequest(), InputOutputUserInfo.class);\n            if (inputCreateUser != null\n                && !StringUtil.isNullOrEmpty(inputCreateUser.getName())\n                && (inputCreateUser.getType() == ProtoConstants.UserType.UserType_Normal || inputCreateUser.getType() == ProtoConstants.UserType.UserType_Admin || inputCreateUser.getType() == ProtoConstants.UserType.UserType_Super_Admin)) {\n\n                if(StringUtil.isNullOrEmpty(inputCreateUser.getUserId())) {\n                    inputCreateUser.setUserId(messagesStore.getShortUUID());\n                }\n\n                WFCMessage.User.Builder newUserBuilder = WFCMessage.User.newBuilder()\n                    .setUid(StringUtil.isNullOrEmpty(inputCreateUser.getUserId()) ? \"\" : inputCreateUser.getUserId());\n                if (inputCreateUser.getName() != null)\n                    newUserBuilder.setName(inputCreateUser.getName());\n                if (inputCreateUser.getDisplayName() != null)\n                    newUserBuilder.setDisplayName(inputCreateUser.getDisplayName());\n                if (inputCreateUser.getPortrait() != null)\n                    newUserBuilder.setPortrait(inputCreateUser.getPortrait());\n                if (inputCreateUser.getEmail() != null)\n                    newUserBuilder.setEmail(inputCreateUser.getEmail());\n                if (inputCreateUser.getAddress() != null)\n                    newUserBuilder.setAddress(inputCreateUser.getAddress());\n                if (inputCreateUser.getCompany() != null)\n                    newUserBuilder.setCompany(inputCreateUser.getCompany());\n                if (inputCreateUser.getSocial() != null)\n                    newUserBuilder.setSocial(inputCreateUser.getSocial());\n                if (inputCreateUser.getMobile() != null)\n                    newUserBuilder.setMobile(inputCreateUser.getMobile());\n                newUserBuilder.setGender(inputCreateUser.getGender());\n                if (inputCreateUser.getExtra() != null)\n                    newUserBuilder.setExtra(inputCreateUser.getExtra());\n\n                newUserBuilder.setType(inputCreateUser.getType());\n                newUserBuilder.setUpdateDt(System.currentTimeMillis());\n\n\n                try {\n                    messagesStore.addUserInfo(newUserBuilder.build());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, IMExceptionEvent.EventType.ADMIN_API_Exception);\n                    setResponseContent(RestResult.resultOf(ErrorCode.ERROR_CODE_SERVER_ERROR, e.getMessage()), response);\n                    return true;\n                }\n\n                setResponseContent(RestResult.ok(new OutputCreateUser(inputCreateUser.getUserId(), inputCreateUser.getName())), response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/DestoryChatroomAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.InputDestoryChatroom;\nimport io.moquette.spi.impl.Utils;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport cn.wildfirechat.common.ErrorCode;\n\n@Route(APIPath.Chatroom_Destroy)\n@HttpMethod(\"POST\")\npublic class DestoryChatroomAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            FullHttpRequest fullHttpRequest = (FullHttpRequest)request.getNettyRequest();\n            byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());\n            String content = new String(bytes);\n            \n            InputDestoryChatroom inputDestoryChatroom = gson.fromJson(content, InputDestoryChatroom.class);\n            if (inputDestoryChatroom != null\n                && !StringUtil.isNullOrEmpty(inputDestoryChatroom.getChatroomId())) {\n                messagesStore.destoryChatroom(inputDestoryChatroom.getChatroomId());\n                setResponseContent(RestResult.ok(), response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/DestroyChannelAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputChannelId;\nimport cn.wildfirechat.pojos.OutputCreateChannel;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Destroy_Channel)\n@HttpMethod(\"POST\")\npublic class DestroyChannelAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputChannelId inputCreateChannel = getRequestBody(request.getNettyRequest(), InputChannelId.class);\n            if (inputCreateChannel != null\n                && !StringUtil.isNullOrEmpty(inputCreateChannel.channelId)) {\n                WFCMessage.ChannelInfo channelInfo = messagesStore.getChannelInfo(inputCreateChannel.channelId);\n                if(channelInfo == null) {\n                    setResponseContent(RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST), response);\n                    return true;\n                }\n\n                WFCMessage.IDBuf.Builder builder = WFCMessage.IDBuf.newBuilder().setId(inputCreateChannel.channelId);\n                sendApiMessage(response, channelInfo.getOwner(), IMTopic.DestroyChannelInfoTopic, builder.build().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/DestroyUserAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputDestroyUser;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.Base64;\n\n@Route(APIPath.Destroy_User)\n@HttpMethod(\"POST\")\npublic class DestroyUserAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputDestroyUser inputDestroyUser = getRequestBody(request.getNettyRequest(), InputDestroyUser.class);\n            if (inputDestroyUser != null\n                && !StringUtil.isNullOrEmpty(inputDestroyUser.getUserId())) {\n\n                WFCMessage.IDBuf idBuf = WFCMessage.IDBuf.newBuilder().setId(inputDestroyUser.getUserId()).build();\n                sendApiMessage(response, inputDestroyUser.getUserId(), IMTopic.DestroyUserTopic, idBuf.toByteArray(), result -> {\n                    ErrorCode errorCode1 = ErrorCode.fromCode(result[0]);\n                    return new Result(errorCode1);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/DismissGroupAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport cn.wildfirechat.pojos.InputDismissGroup;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Group_Dismiss)\n@HttpMethod(\"POST\")\npublic class DismissGroupAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputDismissGroup inputDismissGroup = getRequestBody(request.getNettyRequest(), InputDismissGroup.class);\n            if (inputDismissGroup.isValide()) {\n                sendApiMessage(response, inputDismissGroup.getOperator(), IMTopic.DismissGroupTopic, inputDismissGroup.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/FriendExtraPutAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputUpdateFriendExtra;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Friend_Set_Extra)\n@HttpMethod(\"POST\")\npublic class FriendExtraPutAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputUpdateFriendExtra input = getRequestBody(request.getNettyRequest(), InputUpdateFriendExtra.class);\n            if (input != null && !StringUtil.isNullOrEmpty(input.getOperator()) && !StringUtil.isNullOrEmpty(input.getTargetId())) {\n                sendApiMessage(response, input.getOperator(), IMTopic.SetFriendExtraTopic, WFCMessage.StringPair.newBuilder().setKey(input.getTargetId()).setValue(input.getExtra()==null?\"\":input.getExtra()).build().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/FriendRelationAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport cn.wildfirechat.pojos.InputUpdateFriendStatusRequest;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Friend_Update_Status)\n@HttpMethod(\"POST\")\npublic class FriendRelationAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputUpdateFriendStatusRequest friendAdd = getRequestBody(request.getNettyRequest(), InputUpdateFriendStatusRequest.class);\n            if (friendAdd != null\n                && !StringUtil.isNullOrEmpty(friendAdd.getUserId())\n                && !StringUtil.isNullOrEmpty(friendAdd.getFriendUid())\n            ) {\n                WFCMessage.HandleFriendRequest.Builder friendRequestBuilder = WFCMessage.HandleFriendRequest.newBuilder().setTargetUid(friendAdd.getFriendUid()).setStatus(friendAdd.getStatus());\n                if (!StringUtil.isNullOrEmpty(friendAdd.getExtra())) {\n                    friendRequestBuilder = friendRequestBuilder.setExtra(friendAdd.getExtra());\n                }\n                sendApiMessage(response, friendAdd.getUserId(), IMTopic.HandleFriendRequestTopic, friendRequestBuilder.build().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/FriendRelationGetAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.InputUserId;\nimport cn.wildfirechat.pojos.OutputStringList;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport com.xiaoleilu.loServer.model.FriendData;\nimport cn.wildfirechat.pojos.InputGetFriendList;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\n\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.List;\n\n@Route(APIPath.Friend_Get_List)\n@HttpMethod(\"POST\")\npublic class FriendRelationGetAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputUserId inputGetFriendList = getRequestBody(request.getNettyRequest(), InputUserId.class);\n            List<FriendData> dataList = messagesStore.getFriendList(inputGetFriendList.getUserId(), null, 0);\n            List<String> list = new ArrayList<>();\n            dataList.sort(Comparator.comparingLong(FriendData::getTimestamp));\n            for (FriendData data : dataList) {\n                if (data.getState() == 0) {\n                    list.add(data.getFriendUid());\n                }\n            }\n            setResponseContent(RestResult.ok(new OutputStringList(list)), response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetAllUserAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.InputGetUserList;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.OutputGetUserList;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Route(APIPath.User_Get_All)\n@HttpMethod(\"POST\")\npublic class GetAllUserAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetUserList input = getRequestBody(request.getNettyRequest(), InputGetUserList.class);\n            if (input != null && input.count > 0 && input.offset >= 0) {\n                List<WFCMessage.User> users = messagesStore.getUserInfoList(input.count, input.offset);\n                OutputGetUserList outputGetUserList = new OutputGetUserList();\n                outputGetUserList.userInfoList = new ArrayList<>();\n                for (WFCMessage.User user : users) {\n                    outputGetUserList.userInfoList.add(InputOutputUserInfo.fromPbUser(user));\n                }\n\n                RestResult result = RestResult.ok(outputGetUserList);\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetBatchUserAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\n@Route(APIPath.User_Batch_Get_Infos)\n@HttpMethod(\"POST\")\npublic class GetBatchUserAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputStringList inputUserId = getRequestBody(request.getNettyRequest(), InputStringList.class);\n            if (inputUserId != null && inputUserId.getList() != null && !inputUserId.getList().isEmpty()) {\n\n                OutputUserInfoList res = new OutputUserInfoList();\n                res.userInfos = new ArrayList<>();\n                for (String userId : inputUserId.getList()) {\n                    WFCMessage.User user = messagesStore.getUserInfo(userId);\n                    if(user == null || StringUtil.isNullOrEmpty(user.getName())) {\n                        continue;\n                    }\n                    InputOutputUserInfo inputOutputUserInfo = InputOutputUserInfo.fromPbUser(user);\n                    res.userInfos.add(inputOutputUserInfo);\n                }\n                RestResult result = RestResult.ok(res);\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetChannelAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputChannelId;\nimport cn.wildfirechat.pojos.OutputGetChannelInfo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Get_Channel_Info)\n@HttpMethod(\"POST\")\npublic class GetChannelAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputChannelId inputCreateChannel = getRequestBody(request.getNettyRequest(), InputChannelId.class);\n            if (inputCreateChannel != null\n                && !StringUtil.isNullOrEmpty(inputCreateChannel.channelId)) {\n                WFCMessage.ChannelInfo channelInfo = messagesStore.getChannelInfo(inputCreateChannel.channelId);\n                if (channelInfo == null) {\n                    setResponseContent(RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST), response);\n                } else {\n                    setResponseContent(RestResult.ok(OutputGetChannelInfo.fromPbInfo(channelInfo)), response);\n                }\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetChatroomInfoAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport cn.wildfirechat.common.ErrorCode;\n\n@Route(APIPath.Chatroom_Info)\n@HttpMethod(\"POST\")\npublic class GetChatroomInfoAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetChatroomInfo getChatroomInfo = getRequestBody(request.getNettyRequest(), InputGetChatroomInfo.class);\n            String chatroomid = getChatroomInfo.getChatroomId();\n            if (!StringUtil.isNullOrEmpty(chatroomid)) {\n\n                WFCMessage.ChatroomInfo info = messagesStore.getChatroomInfo(chatroomid);\n\n                RestResult result;\n                if (info != null) {\n                    result = RestResult.ok(new OutputGetChatroomInfo(chatroomid, messagesStore.getChatroomMemberCount(chatroomid), info));\n                } else {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                }\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetChatroomMembersAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetChatroomInfo;\nimport cn.wildfirechat.pojos.OutputGetChatroomInfo;\nimport cn.wildfirechat.pojos.OutputStringList;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.UserClientEntry;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\n@Route(APIPath.Chatroom_GetMembers)\n@HttpMethod(\"POST\")\npublic class GetChatroomMembersAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetChatroomInfo getChatroomInfo = getRequestBody(request.getNettyRequest(), InputGetChatroomInfo.class);\n            String chatroomid = getChatroomInfo.getChatroomId();\n            if (!StringUtil.isNullOrEmpty(chatroomid)) {\n\n                Collection<UserClientEntry> members = messagesStore.getChatroomMembers(chatroomid);\n\n                List<String> list = new ArrayList<>();\n                for (UserClientEntry entry : members) {\n                    list.add(entry.userId);\n                }\n\n                RestResult result;\n                if (!list.isEmpty()) {\n                    result = RestResult.ok(new OutputStringList(list));\n                } else {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                }\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetCommonGroupsAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputUserId;\nimport cn.wildfirechat.pojos.OutputGroupIds;\nimport cn.wildfirechat.pojos.StringPairPojo;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.Set;\n\n@Route(APIPath.Get_Common_Groups)\n@HttpMethod(\"POST\")\npublic class GetCommonGroupsAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            StringPairPojo input = getRequestBody(request.getNettyRequest(), StringPairPojo.class);\n            if (input != null\n                && (!StringUtil.isNullOrEmpty(input.getFirst())) && (!StringUtil.isNullOrEmpty(input.getSecond()))) {\n\n                Set<String> groupIds = messagesStore.getCommonGroupIds(input.getFirst(), input.getSecond());\n                OutputGroupIds outputGroupIds = new OutputGroupIds();\n                outputGroupIds.setGroupIds(new ArrayList<>(groupIds));\n                RestResult result = RestResult.ok(outputGroupIds);\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetGroupInfoAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetGroup;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.PojoGroupInfo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Group_Get_Info)\n@HttpMethod(\"POST\")\npublic class GetGroupInfoAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetGroup inputGetGroup = getRequestBody(request.getNettyRequest(), InputGetGroup.class);\n            if (inputGetGroup != null\n                && (!StringUtil.isNullOrEmpty(inputGetGroup.getGroupId()))) {\n\n                WFCMessage.GroupInfo groupInfo = messagesStore.getGroupInfo(inputGetGroup.getGroupId());\n                RestResult result;\n                if (groupInfo == null) {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                } else {\n                    PojoGroupInfo pojoGroupInfo = new PojoGroupInfo();\n                    pojoGroupInfo.setExtra(groupInfo.getExtra());\n                    pojoGroupInfo.setName(groupInfo.getName());\n                    pojoGroupInfo.setOwner(groupInfo.getOwner());\n                    pojoGroupInfo.setPortrait(groupInfo.getPortrait());\n                    pojoGroupInfo.setTarget_id(groupInfo.getTargetId());\n                    pojoGroupInfo.setType(groupInfo.getType());\n                    pojoGroupInfo.setMember_count(groupInfo.getMemberCount());\n                    pojoGroupInfo.setMute(groupInfo.getMute());\n                    pojoGroupInfo.setJoin_type(groupInfo.getJoinType());\n                    pojoGroupInfo.setPrivate_chat(groupInfo.getPrivateChat());\n                    pojoGroupInfo.setSearchable(groupInfo.getSearchable());\n                    pojoGroupInfo.setMax_member_count(groupInfo.getMemberCount());\n                    pojoGroupInfo.setHistory_message(groupInfo.getHistoryMessage());\n                    pojoGroupInfo.setSuper_group(groupInfo.getSuperGroup()>0);\n                    pojoGroupInfo.setDeleted(groupInfo.getDeleted()>0);\n                    pojoGroupInfo.setUpdate_dt(groupInfo.getUpdateDt());\n                    pojoGroupInfo.setMember_update_dt(groupInfo.getMemberUpdateDt());\n                    result = RestResult.ok(pojoGroupInfo);\n                }\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetGroupMemberAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetGroup;\nimport cn.wildfirechat.pojos.InputGetGroupMember;\nimport cn.wildfirechat.pojos.OutputGroupMemberList;\nimport cn.wildfirechat.pojos.PojoGroupMember;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Route(APIPath.Group_Member_Get)\n@HttpMethod(\"POST\")\npublic class GetGroupMemberAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetGroupMember input = getRequestBody(request.getNettyRequest(), InputGetGroupMember.class);\n            if (input != null\n                && (!StringUtil.isNullOrEmpty(input.getGroupId()))\n                && (!StringUtil.isNullOrEmpty(input.getMemberId()))) {\n\n                WFCMessage.GroupMember groupMember = messagesStore.getGroupMember(input.getGroupId(), input.getMemberId());\n\n                RestResult result;\n                if (groupMember == null || StringUtil.isNullOrEmpty(groupMember.getMemberId()) || groupMember.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Removed) {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                } else {\n                    PojoGroupMember pm = new PojoGroupMember();\n                    pm.setMember_id(groupMember.getMemberId());\n                    pm.setAlias(groupMember.getAlias());\n                    pm.setType(groupMember.getType());\n                    pm.setExtra(groupMember.getExtra());\n                    pm.setCreateDt(groupMember.getCreateDt());\n                    result = RestResult.ok(pm);\n                }\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetGroupMembersAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetGroup;\nimport cn.wildfirechat.pojos.OutputGroupMemberList;\nimport cn.wildfirechat.pojos.PojoGroupInfo;\nimport cn.wildfirechat.pojos.PojoGroupMember;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Route(APIPath.Group_Member_List)\n@HttpMethod(\"POST\")\npublic class GetGroupMembersAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetGroup inputGetGroup = getRequestBody(request.getNettyRequest(), InputGetGroup.class);\n            if (inputGetGroup != null\n                && (!StringUtil.isNullOrEmpty(inputGetGroup.getGroupId()))) {\n\n                List<WFCMessage.GroupMember> members = new ArrayList<>();\n                ErrorCode errorCode = messagesStore.getGroupMembers(null, inputGetGroup.getGroupId(), 0, members);\n\n                RestResult result;\n                if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                    result = RestResult.resultOf(errorCode);\n                } else {\n                    OutputGroupMemberList out = new OutputGroupMemberList();\n                    out.setMembers(new ArrayList<>());\n                    for (WFCMessage.GroupMember member : members) {\n                        if (member.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Removed) {\n                            continue;\n                        }\n                        PojoGroupMember pm = new PojoGroupMember();\n                        pm.setMember_id(member.getMemberId());\n                        pm.setAlias(member.getAlias());\n                        pm.setType(member.getType());\n                        pm.setExtra(member.getExtra());\n                        pm.setCreateDt(member.getCreateDt());\n                        out.getMembers().add(pm);\n                    }\n                    result = RestResult.ok(out);\n                }\n\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetIMTokenAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport cn.wildfirechat.pojos.InputGetToken;\nimport cn.wildfirechat.pojos.OutputGetIMTokenData;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport cn.wildfirechat.common.ErrorCode;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.GitRepositoryState;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.Base64;\n\n@Route(APIPath.User_Get_Token)\n@HttpMethod(\"POST\")\npublic class GetIMTokenAction extends AdminAction {\n    private static final Logger LOG = LoggerFactory.getLogger(GetIMTokenAction.class);\n    @Override\n    public boolean isTransactionAction() {\n        return false;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetToken input = getRequestBody(request.getNettyRequest(), InputGetToken.class);\n            String userId = input.getUserId();\n\n\n            WFCMessage.GetTokenRequest getTokenRequest = WFCMessage.GetTokenRequest.newBuilder().setUserId(userId).setClientId(input.getClientId()).setPlatform(input.getPlatform() == null ? 0 : input.getPlatform()).build();\n            sendApiMessage(response, userId, input.getClientId(), IMTopic.GetTokenTopic, getTokenRequest.toByteArray(), result -> {\n                ErrorCode errorCode1 = ErrorCode.fromCode(result[0]);\n                if (errorCode1 == ErrorCode.ERROR_CODE_SUCCESS) {\n                    //ba errorcode qudiao\n                    byte[] data = new byte[result.length -1];\n                    for (int i = 0; i < data.length; i++) {\n                        data[i] = result[i+1];\n                    }\n                    String token = Base64.getEncoder().encodeToString(data);\n\n                    LOG.info(\"get im token success {},{},{}\", userId, input.getClientId(), token.substring(0, Math.min(10, token.length())));\n                    \n                    return new Result(errorCode1, new OutputGetIMTokenData(userId, token, GitRepositoryState.globalLabel));\n                } else {\n                    return new Result(errorCode1);\n                }\n            }, false);\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetMessageAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputMessageUid;\nimport cn.wildfirechat.pojos.OutputMessageData;\nimport cn.wildfirechat.pojos.RecallMessageData;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Msg_GetOne)\n@HttpMethod(\"POST\")\npublic class GetMessageAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputMessageUid inputMessageUid = getRequestBody(request.getNettyRequest(), InputMessageUid.class);\n            if (inputMessageUid != null && inputMessageUid.messageUid > 0) {\n                RestResult result;\n                WFCMessage.Message msg = messagesStore.getMessage(inputMessageUid.messageUid);\n                if(msg == null) {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                } else {\n                    result = RestResult.ok(OutputMessageData.fromProtoMessage(msg));\n                }\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetOnlineUserAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.*;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.Collection;\n\n@Route(APIPath.User_Online_List)\n@HttpMethod(\"POST\")\npublic class GetOnlineUserAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            GetOnlineUserRequest getOnlineUserRequest = getRequestBody(request.getNettyRequest(), GetOnlineUserRequest.class);\n            if (getOnlineUserRequest.nodeId == 1) {\n                GetOnlineUserResult result = messagesStore.getOnlineUsers(getOnlineUserRequest.offset, getOnlineUserRequest.count);\n                setResponseContent(RestResult.ok(result), response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetRobotAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.InputRobotId;\nimport cn.wildfirechat.pojos.OutputRobot;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.User_Get_Robot_Info)\n@HttpMethod(\"POST\")\npublic class GetRobotAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputRobotId inputUserId = getRequestBody(request.getNettyRequest(), InputRobotId.class);\n            if (inputUserId != null\n                && (!StringUtil.isNullOrEmpty(inputUserId.getRobotId()))) {\n\n                WFCMessage.User user = messagesStore.getUserInfo(inputUserId.getRobotId());\n                WFCMessage.Robot robot = messagesStore.getRobot(inputUserId.getRobotId());\n\n                RestResult result;\n                if (user == null || robot == null) {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                } else {\n                    OutputRobot outputRobot = new OutputRobot();\n                    outputRobot.fromUser(user);\n                    outputRobot.fromRobot(robot, true);\n                    result = RestResult.ok(outputRobot);\n                }\n\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetSystemSettingAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.SystemSettingPojo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Get_System_Setting)\n@HttpMethod(\"POST\")\npublic class GetSystemSettingAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return false;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            SystemSettingPojo inputUserId = getRequestBody(request.getNettyRequest(), SystemSettingPojo.class);\n            if (inputUserId != null) {\n                SystemSettingPojo output = messagesStore.getSystemSetting(inputUserId.id);\n\n                RestResult result;\n                if (output == null) {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                } else {\n                    result = RestResult.ok(output);\n                }\n\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetUploadUrlAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetPresignedUploadUrl;\nimport cn.wildfirechat.pojos.OutputPresignedUploadUrl;\nimport com.qiniu.util.Auth;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.action.robot.RobotAction;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.server.config.MediaServerConfig;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.UUID;\n\n@Route(APIPath.Get_Presigned_Upload_Url)\n@HttpMethod(\"POST\")\npublic class GetUploadUrlAction extends AdminAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            if(!MediaServerConfig.USER_QINIU) {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n                return true;\n            }\n\n            InputGetPresignedUploadUrl inputUserId = getRequestBody(request.getNettyRequest(), InputGetPresignedUploadUrl.class);\n\n            if (StringUtil.isNullOrEmpty(inputUserId.contentType)) {\n                inputUserId.contentType = \"application/octet-stream\";\n            }\n            String uuid = UUID.randomUUID().toString().replace(\"-\", \"\");\n            inputUserId.fileName = uuid + inputUserId.fileName;\n\n            int type = inputUserId.mediaType;\n            String bucketName;\n            String bucketDomain;\n            switch (type) {\n                case 0:\n                default:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_GENERAL_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN;\n                    break;\n                case 1:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_IMAGE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_IMAGE_DOMAIN;\n                    break;\n                case 2:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_VOICE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_VOICE_DOMAIN;\n                    break;\n                case 3:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_VIDEO_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_VIDEO_DOMAIN;\n                    break;\n                case 4:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_FILE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_FILE_DOMAIN;\n                    break;\n                case 5:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_PORTRAIT_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_PORTRAIT_DOMAIN;\n                    break;\n                case 6:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_FAVORITE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_FAVORITE_DOMAIN;\n                    break;\n                case 7:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_STICKER_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_STICKER_DOMAIN;\n                    break;\n                case 8:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_MOMENTS_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_MOMENTS_DOMAIN;\n                    break;\n                case 9:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_CUSTOM1_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_CUSTOM1_DOMAIN;\n                    break;\n                case 10:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_CUSTOM2_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_CUSTOM2_DOMAIN;\n                    break;\n                case 11:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_CUSTOM3_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_CUSTOM3_DOMAIN;\n                    break;\n                case 12:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_PAN_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_PAN_DOMAIN;\n                    break;\n            }\n\n            if(StringUtil.isNullOrEmpty(bucketName)) {\n                bucketName = MediaServerConfig.QINIU_BUCKET_GENERAL_NAME;\n                bucketDomain = MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN;\n            }\n\n            String key = inputUserId.fileName;\n            Auth auth = Auth.create(MediaServerConfig.QINIU_ACCESS_KEY, MediaServerConfig.QINIU_SECRET_KEY);\n            String token = auth.uploadToken(bucketName, key);\n            String downloadUrl = bucketDomain + \"/\" + key;\n            String uploadUrl = \"https://\" + MediaServerConfig.QINIU_SERVER_URL + \"?\" + token + \"?\" + key;\n\n            OutputPresignedUploadUrl outputPresignedUploadUrl = new OutputPresignedUploadUrl();\n            outputPresignedUploadUrl.uploadUrl = uploadUrl;\n            outputPresignedUploadUrl.downloadUrl = downloadUrl;\n            outputPresignedUploadUrl.type = 1;\n            setResponseContent(RestResult.ok(outputPresignedUploadUrl), response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetUserAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport cn.wildfirechat.common.ErrorCode;\n\n@Route(APIPath.User_Get_Info)\n@HttpMethod(\"POST\")\npublic class GetUserAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetUserInfo inputUserId = getRequestBody(request.getNettyRequest(), InputGetUserInfo.class);\n            if (inputUserId != null\n                && (!StringUtil.isNullOrEmpty(inputUserId.getUserId()) || !StringUtil.isNullOrEmpty(inputUserId.getName()) || !StringUtil.isNullOrEmpty(inputUserId.getMobile()))) {\n\n                WFCMessage.User user = null;\n                if(!StringUtil.isNullOrEmpty(inputUserId.getUserId())) {\n                    user = messagesStore.getUserInfo(inputUserId.getUserId());\n                } else if(!StringUtil.isNullOrEmpty(inputUserId.getName())) {\n                    user = messagesStore.getUserInfoByName(inputUserId.getName());\n                } else if(!StringUtil.isNullOrEmpty(inputUserId.getMobile())) {\n                    user = messagesStore.getUserInfoByMobile(inputUserId.getMobile());\n                }\n\n                RestResult result;\n                if (user == null || (user.getDeleted() > 0 && !inputUserId.isIncludeDeleted())) {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                } else {\n                    result = RestResult.ok(InputOutputUserInfo.fromPbUser(user));\n                }\n\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetUserBlockListAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.OutputUserBlockStatusList;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\n\n@Route(APIPath.User_Get_Blocked_List)\n@HttpMethod(\"POST\")\npublic class GetUserBlockListAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            OutputUserBlockStatusList list = new OutputUserBlockStatusList();\n            list.setStatusList(messagesStore.getUserStatusList());\n            RestResult result = RestResult.ok(list);\n            setResponseContent(result, response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetUserBlockStatusAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.OutputUserStatus;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport cn.wildfirechat.common.ErrorCode;\n\n@Route(APIPath.User_Check_Block_Status)\n@HttpMethod(\"POST\")\npublic class GetUserBlockStatusAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetUserInfo inputUserId = getRequestBody(request.getNettyRequest(), InputGetUserInfo.class);\n            if (inputUserId != null\n                && !StringUtil.isNullOrEmpty(inputUserId.getUserId())) {\n\n                int status = messagesStore.getUserStatus(inputUserId.getUserId());\n                setResponseContent(RestResult.ok(new OutputUserStatus(status)), response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetUserChatroomAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetChatroomInfo;\nimport cn.wildfirechat.pojos.InputUserId;\nimport cn.wildfirechat.pojos.OutputStringList;\nimport cn.wildfirechat.pojos.OutputUserChatroom;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.UserClientEntry;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\n@Route(APIPath.Chatroom_GetUserChatroom)\n@HttpMethod(\"POST\")\npublic class GetUserChatroomAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputUserId inputUserId = getRequestBody(request.getNettyRequest(), InputUserId.class);\n            String userId = inputUserId.getUserId();\n            if (!StringUtil.isNullOrEmpty(userId)) {\n                OutputUserChatroom outputUserChatroom = messagesStore.getUserChatroom(userId);\n\n                RestResult result;\n                if (outputUserChatroom != null) {\n                    result = RestResult.ok(outputUserChatroom);\n                } else {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                }\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetUserGroupsAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetGroup;\nimport cn.wildfirechat.pojos.InputUserId;\nimport cn.wildfirechat.pojos.OutputGroupIds;\nimport cn.wildfirechat.pojos.PojoGroupInfo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.Set;\n\n@Route(APIPath.Get_User_Groups)\n@HttpMethod(\"POST\")\npublic class GetUserGroupsAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputUserId inputUserId = getRequestBody(request.getNettyRequest(), InputUserId.class);\n            if (inputUserId != null\n                && (!StringUtil.isNullOrEmpty(inputUserId.getUserId()))) {\n\n                Set<String> groupIds = messagesStore.getUserGroupIds(inputUserId.getUserId());\n                OutputGroupIds outputGroupIds = new OutputGroupIds();\n                outputGroupIds.setGroupIds(new ArrayList<>(groupIds));\n                RestResult result = RestResult.ok(outputGroupIds);\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetUserGroupsByTypeAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetUserGroupByType;\nimport cn.wildfirechat.pojos.InputUserId;\nimport cn.wildfirechat.pojos.OutputGroupIds;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.Set;\n\n@Route(APIPath.Get_User_Groups_By_Type)\n@HttpMethod(\"POST\")\npublic class GetUserGroupsByTypeAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetUserGroupByType input = getRequestBody(request.getNettyRequest(), InputGetUserGroupByType.class);\n            if (input != null\n                && (!StringUtil.isNullOrEmpty(input.getUserId()))) {\n\n                Set<String> groupIds = messagesStore.getUserGroupIds(input.getUserId(), input.getGroupMemberTypes());\n                OutputGroupIds outputGroupIds = new OutputGroupIds();\n                outputGroupIds.setGroupIds(new ArrayList<>(groupIds));\n                RestResult result = RestResult.ok(outputGroupIds);\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetUserOnlineCountAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.GetOnlineUserCountResult;\nimport cn.wildfirechat.pojos.GetUserSessionResult;\nimport cn.wildfirechat.pojos.InputUserId;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.Collection;\n\n@Route(APIPath.User_Online_Count)\n@HttpMethod(\"POST\")\npublic class GetUserOnlineCountAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            int count = messagesStore.getOnlineUserCount();\n            GetOnlineUserCountResult result = new GetOnlineUserCountResult();\n            GetOnlineUserCountResult.Node node = new GetOnlineUserCountResult.Node();\n            node.node = 1;\n            node.count = count;\n            result.add(node);\n\n            setResponseContent(RestResult.ok(result), response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetUserRobotsAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputRobotId;\nimport cn.wildfirechat.pojos.InputUserId;\nimport cn.wildfirechat.pojos.OutputRobot;\nimport cn.wildfirechat.pojos.OutputStringList;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.User_Get_User_Robots)\n@HttpMethod(\"POST\")\npublic class GetUserRobotsAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputUserId inputUserId = getRequestBody(request.getNettyRequest(), InputUserId.class);\n            if (inputUserId != null\n                && (!StringUtil.isNullOrEmpty(inputUserId.getUserId()))) {\n                RestResult result = RestResult.ok(new OutputStringList(messagesStore.getUserRobotIds(inputUserId.getUserId())));\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetUserSessionsAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.GetUserSessionResult;\nimport cn.wildfirechat.pojos.InputGetChatroomInfo;\nimport cn.wildfirechat.pojos.InputUserId;\nimport cn.wildfirechat.pojos.OutputStringList;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.Collection;\n\n@Route(APIPath.User_Session_List)\n@HttpMethod(\"POST\")\npublic class GetUserSessionsAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputUserId inputUserId = getRequestBody(request.getNettyRequest(), InputUserId.class);\n            String userId = inputUserId.getUserId();\n            if (!StringUtil.isNullOrEmpty(userId)) {\n                Collection<MemorySessionStore.Session> sessions = sessionsStore.sessionForUser(userId);\n                GetUserSessionResult result = new GetUserSessionResult();\n                for (MemorySessionStore.Session session : sessions) {\n                    boolean isOnline = sessionsStore.isClientOnline(session.getClientID());\n                    result.userSessions.add(new GetUserSessionResult.UserSession(session.getUsername(), session.getClientID(), session.getPlatform(), session.getPushType(), session.getDeviceToken(), session.getVoipDeviceToken(), isOnline));\n                }\n\n                setResponseContent(RestResult.ok(result), response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/GetUsersByEmailAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.OutputUserInfoList;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Route(APIPath.User_Get_Email_Info)\n@HttpMethod(\"POST\")\npublic class GetUsersByEmailAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            String email = getRequestBody(request.getNettyRequest(), String.class);\n            if (!StringUtil.isNullOrEmpty(email)) {\n\n                List<WFCMessage.User> users = messagesStore.getUserInfosByEmail(email);\n                List<InputOutputUserInfo> list = new ArrayList<>();\n                for (WFCMessage.User user : users) {\n                    list.add(InputOutputUserInfo.fromPbUser(user));\n                }\n\n                RestResult result;\n                if (list.isEmpty()) {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                } else {\n                    OutputUserInfoList outputUserInfoList = new OutputUserInfoList();\n                    outputUserInfoList.userInfos = list;\n                    result = RestResult.ok(outputUserInfoList);\n                }\n\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/HealthAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.OutputUserBlockStatusList;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\n\nimport java.io.File;\nimport java.lang.management.OperatingSystemMXBean;\n\nimport static java.lang.management.ManagementFactory.getOperatingSystemMXBean;\n\n@Route(APIPath.Health)\npublic class HealthAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            JSONObject jsonObject = new JSONObject();\n\n            jsonObject.put(\"node\", \"1\");\n\n            JSONObject cpuObject = new JSONObject();\n            jsonObject.put(\"cpu\", cpuObject);\n\n            JSONObject memoryObject = new JSONObject();\n            jsonObject.put(\"memory\", memoryObject);\n\n            JSONObject fileObject = new JSONObject();\n            jsonObject.put(\"disk\", fileObject);\n\n            if (getOperatingSystemMXBean() instanceof OperatingSystemMXBean) {\n                double load = getOperatingSystemMXBean().getSystemLoadAverage();\n                cpuObject.put(\"load\", load);\n            }\n            cpuObject.put(\"cores\", Runtime.getRuntime().availableProcessors());\n\n            memoryObject.put(\"free\", Runtime.getRuntime().freeMemory());\n            memoryObject.put(\"max\", Runtime.getRuntime().maxMemory());\n            memoryObject.put(\"avail\", Runtime.getRuntime().totalMemory());\n\n            File root = new File(\"/\");\n            fileObject.put(\"space\", root.getTotalSpace());\n            fileObject.put(\"free\", root.getFreeSpace());\n            fileObject.put(\"usable\", root.getUsableSpace());\n\n            JSONArray out = new JSONArray();\n            out.add(jsonObject);\n            RestResult result = RestResult.ok(out);\n            setResponseContent(result, response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/KickoffGroupMemberAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport cn.wildfirechat.pojos.InputKickoffGroupMember;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Group_Member_Kickoff)\n@HttpMethod(\"POST\")\npublic class KickoffGroupMemberAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputKickoffGroupMember inputKickoffGroupMember = getRequestBody(request.getNettyRequest(), InputKickoffGroupMember.class);\n            if (inputKickoffGroupMember.isValide()) {\n                sendApiMessage(response, inputKickoffGroupMember.getOperator(), IMTopic.KickoffGroupMemberTopic, inputKickoffGroupMember.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/KickoffUserClientAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.StringPairPojo;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.User_Kickoff_Client)\n@HttpMethod(\"POST\")\npublic class KickoffUserClientAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            StringPairPojo pojo = getRequestBody(request.getNettyRequest(), StringPairPojo.class);\n            if (pojo != null && !StringUtil.isNullOrEmpty(pojo.getFirst())) {\n                sessionsStore.kickoffUserClient(pojo.getFirst(), pojo.getSecond());\n                sendResponse(response, ErrorCode.ERROR_CODE_SUCCESS, null);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/ModifyGroupInfoAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputModifyGroupInfo;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Group_Modify_Info)\n@HttpMethod(\"POST\")\npublic class ModifyGroupInfoAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputModifyGroupInfo inputAddGroupMember = getRequestBody(request.getNettyRequest(), InputModifyGroupInfo.class);\n            if (inputAddGroupMember.isValide()) {\n                sendApiMessage(response, inputAddGroupMember.getOperator(), IMTopic.ModifyGroupInfoTopic, inputAddGroupMember.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/ModifyGroupMemberAliasAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputSetGroupMemberAlias;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Group_Set_Member_Alias)\n@HttpMethod(\"POST\")\npublic class ModifyGroupMemberAliasAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputSetGroupMemberAlias inputSetGroupMemberAlias = getRequestBody(request.getNettyRequest(), InputSetGroupMemberAlias.class);\n            if (inputSetGroupMemberAlias.isValide()) {\n                sendApiMessage(response, inputSetGroupMemberAlias.getOperator(), IMTopic.ModifyGroupMemberAliasTopic, inputSetGroupMemberAlias.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/ModifyGroupMemberExtraAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputSetGroupMemberExtra;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.concurrent.Executor;\n\n@Route(APIPath.Group_Set_Member_Extra)\n@HttpMethod(\"POST\")\npublic class ModifyGroupMemberExtraAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputSetGroupMemberExtra inputSetGroupMemberExtra = getRequestBody(request.getNettyRequest(), InputSetGroupMemberExtra.class);\n            if (inputSetGroupMemberExtra.isValide()) {\n                sendApiMessage(response, inputSetGroupMemberExtra.getOperator(), IMTopic.ModifyGroupMemberExtraTopic, inputSetGroupMemberExtra.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                response.setStatus(HttpResponseStatus.OK);\n                RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);\n                response.setContent(gson.toJson(result));\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/MulticastMessageAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.MultiMessageResult;\nimport cn.wildfirechat.pojos.MulticastMessageData;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Msg_Multicast)\n@HttpMethod(\"POST\")\npublic class MulticastMessageAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            MulticastMessageData sendMessageData = getRequestBody(request.getNettyRequest(), MulticastMessageData.class);\n            if (MulticastMessageData.isValide(sendMessageData)) {\n                sendApiMessage(response, sendMessageData.getSender(), IMTopic.MultiCastMessageTopic, sendMessageData.toProtoMessage().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        long messageId = byteBuf.readLong();\n                        long timestamp = byteBuf.readLong();\n                        return new Result(errorCode, new MultiMessageResult(messageId, timestamp));\n                    } else {\n                        return new Result(errorCode);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/PutSystemSettingAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.SystemSettingPojo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Put_System_Setting)\n@HttpMethod(\"POST\")\npublic class PutSystemSettingAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            SystemSettingPojo inputUserId = getRequestBody(request.getNettyRequest(), SystemSettingPojo.class);\n            if (inputUserId != null\n                && (!StringUtil.isNullOrEmpty(inputUserId.value) || !StringUtil.isNullOrEmpty(inputUserId.desc))) {\n\n                boolean success = messagesStore.updateSystemSetting(inputUserId.id, inputUserId.value, inputUserId.desc);\n                RestResult result;\n                if (!success) {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_SERVER_ERROR);\n                } else {\n                    result = RestResult.ok();\n                }\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/QuitGroupMemberAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputQuitGroup;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Group_Member_Quit)\n@HttpMethod(\"POST\")\npublic class QuitGroupMemberAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputQuitGroup inputQuitGroup = getRequestBody(request.getNettyRequest(), InputQuitGroup.class);\n            if (inputQuitGroup.isValide()) {\n                sendApiMessage(response, inputQuitGroup.getOperator(), IMTopic.QuitGroupTopic, inputQuitGroup.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/RecallMessageAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport cn.wildfirechat.pojos.RecallMessageData;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\n\n@Route(APIPath.Msg_Recall)\n@HttpMethod(\"POST\")\npublic class RecallMessageAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            RecallMessageData recallMessageData = getRequestBody(request.getNettyRequest(), RecallMessageData.class);\n            if (recallMessageData != null && !StringUtil.isNullOrEmpty(recallMessageData.getOperator())) {\n\n                WFCMessage.INT64Buf idBuf = WFCMessage.INT64Buf.newBuilder().setId(recallMessageData.getMessageUid()).build();\n                sendApiMessage(response, recallMessageData.getOperator(), IMTopic.RecallMessageTopic, idBuf.toByteArray(), result -> {\n                    ErrorCode errorCode = ErrorCode.fromCode(result[0]);\n                    byte[] data = Arrays.copyOfRange(result,1, result.length);\n                    return new Result(errorCode, new String(data, StandardCharsets.UTF_8));\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/RecallMultiCastMessageAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.RecallMultiCastMessageData;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Msg_RecallMultiCast)\n@HttpMethod(\"POST\")\npublic class RecallMultiCastMessageAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            RecallMultiCastMessageData recallMessageData = getRequestBody(request.getNettyRequest(), RecallMultiCastMessageData.class);\n            if (recallMessageData != null && !StringUtil.isNullOrEmpty(recallMessageData.operator)) {\n\n                WFCMessage.RecallMultiCastMessageRequest recallRequest = WFCMessage.RecallMultiCastMessageRequest.newBuilder().setMessageId(recallMessageData.messageUid).addAllReceiver(recallMessageData.receivers).build();\n                sendApiMessage(response, recallMessageData.operator, IMTopic.RecallMultiCastMessageTopic, recallRequest.toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/RelationGetAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.InputUserId;\nimport cn.wildfirechat.pojos.OutputStringList;\nimport cn.wildfirechat.pojos.RelationPojo;\nimport cn.wildfirechat.pojos.StringPairPojo;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport com.xiaoleilu.loServer.model.FriendData;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\n\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.List;\n\n@Route(APIPath.Relation_Get)\n@HttpMethod(\"POST\")\npublic class RelationGetAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            StringPairPojo input = getRequestBody(request.getNettyRequest(), StringPairPojo.class);\n            FriendData data = messagesStore.getFriendData(input.getFirst(), input.getSecond());\n\n            RelationPojo out = new RelationPojo();\n            out.userId = input.getFirst();\n            out.targetId = input.getSecond();\n            if(data != null ) {\n                out.isFriend = data.getState() == 0;\n                out.isBlacked = data.getBlacked() == 1;\n                out.alias = data.getAlias();\n                out.extra = data.getExtra();\n            }\n            setResponseContent(RestResult.ok(out), response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/SendMessageAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport com.google.gson.Gson;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport cn.wildfirechat.pojos.SendMessageData;\nimport cn.wildfirechat.pojos.SendMessageResult;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Msg_Send)\n@HttpMethod(\"POST\")\npublic class SendMessageAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            SendMessageData sendMessageData = getRequestBody(request.getNettyRequest(), SendMessageData.class);\n            if (SendMessageData.isValide(sendMessageData) && !StringUtil.isNullOrEmpty(sendMessageData.getSender())) {\n                sendApiMessage(response, sendMessageData.getSender(), IMTopic.SendMessageTopic, sendMessageData.toProtoMessage().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        long messageId = byteBuf.readLong();\n                        long timestamp = byteBuf.readLong();\n                        return new Result(errorCode, new SendMessageResult(messageId, timestamp));\n                    } else {\n                        return new Result(errorCode);\n                    }\n                }, sendMessageData.isUserMessage());\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/SensitiveWordAddAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.InputOutputSensitiveWords;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport cn.wildfirechat.common.ErrorCode;\n\n@Route(APIPath.Sensitive_Add)\n@HttpMethod(\"POST\")\npublic class SensitiveWordAddAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputOutputSensitiveWords input = getRequestBody(request.getNettyRequest(), InputOutputSensitiveWords.class);\n            if (input != null && input.getWords() != null && !input.getWords().isEmpty()) {\n                ErrorCode errorCode = messagesStore.addSensitiveWords(input.getWords()) ? ErrorCode.ERROR_CODE_SUCCESS : ErrorCode.ERROR_CODE_SERVER_ERROR;\n                response.setStatus(HttpResponseStatus.OK);\n                sendResponse(response, errorCode, null);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/SensitiveWordDeleteAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.InputOutputSensitiveWords;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport cn.wildfirechat.common.ErrorCode;\n\n@Route(APIPath.Sensitive_Del)\n@HttpMethod(\"POST\")\npublic class SensitiveWordDeleteAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputOutputSensitiveWords input = getRequestBody(request.getNettyRequest(), InputOutputSensitiveWords.class);\n            if (input != null && input.getWords() != null && !input.getWords().isEmpty()) {\n                ErrorCode errorCode = messagesStore.removeSensitiveWords(input.getWords()) ? ErrorCode.ERROR_CODE_SUCCESS : ErrorCode.ERROR_CODE_SERVER_ERROR;\n                response.setStatus(HttpResponseStatus.OK);\n\n                sendResponse(response, errorCode, null);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/SensitiveWordQueryAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.InputOutputSensitiveWords;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport cn.wildfirechat.common.ErrorCode;\n\nimport java.util.List;\n\n@Route(APIPath.Sensitive_Query)\n@HttpMethod(\"POST\")\npublic class SensitiveWordQueryAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n                List<String> words = messagesStore.getAllSensitiveWords();\n                InputOutputSensitiveWords out = new InputOutputSensitiveWords();\n                out.setWords(words);\n                sendResponse(response, ErrorCode.ERROR_CODE_SUCCESS, out);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/SetGroupManagerAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputSetGroupManager;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Group_Set_Manager)\n@HttpMethod(\"POST\")\npublic class SetGroupManagerAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputSetGroupManager inputAddGroupMember = getRequestBody(request.getNettyRequest(), InputSetGroupManager.class);\n            if (inputAddGroupMember.isValide()) {\n                sendApiMessage(response, inputAddGroupMember.getOperator(), IMTopic.SetGroupManagerTopic, inputAddGroupMember.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/TransferGroupAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport cn.wildfirechat.pojos.InputTransferGroup;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Group_Transfer)\n@HttpMethod(\"POST\")\npublic class TransferGroupAction extends AdminAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputTransferGroup inputDismissGroup = getRequestBody(request.getNettyRequest(), InputTransferGroup.class);\n            if (inputDismissGroup.isValide()) {\n                sendApiMessage(response, inputDismissGroup.getOperator(), IMTopic.TransferGroupTopic, inputDismissGroup.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    return new Result(errorCode);\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/admin/UpdateUserAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.admin;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.common.IMExceptionEvent;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.InputUpdateUserInfo;\nimport cn.wildfirechat.pojos.OutputCreateUser;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.UUIDGenerator;\nimport win.liyufan.im.Utility;\n\n@Route(APIPath.Update_User)\n@HttpMethod(\"POST\")\npublic class UpdateUserAction extends AdminAction {\n    private static final Logger LOG = LoggerFactory.getLogger(UpdateUserAction.class);\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputUpdateUserInfo inputCreateUser = getRequestBody(request.getNettyRequest(), InputUpdateUserInfo.class);\n            if (inputCreateUser != null\n                && inputCreateUser.userInfo != null\n                && !StringUtil.isNullOrEmpty(inputCreateUser.userInfo.getUserId())\n                && inputCreateUser.flag > 0) {\n\n                ErrorCode errorCode = messagesStore.updateUserInfo(inputCreateUser.userInfo, inputCreateUser.flag);\n                setResponseContent(RestResult.resultOf(errorCode), response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/channel/ApplicationGetUserInfoAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.channel;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputApplicationGetUserInfo;\nimport cn.wildfirechat.pojos.OutputApplicationUserInfo;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Channel_Application_Get_UserInfo)\n@HttpMethod(\"POST\")\npublic class ApplicationGetUserInfoAction extends ChannelAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputApplicationGetUserInfo inputUserToken = getRequestBody(request.getNettyRequest(), InputApplicationGetUserInfo.class);\n            RestResult result;\n            if (inputUserToken == null || StringUtil.isNullOrEmpty(inputUserToken.getAuthCode())) {\n                result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);\n            } else {\n                String userId = messagesStore.verifyApplicationAuthCode(inputUserToken.getAuthCode(), channelInfo.getTargetId(), ProtoConstants.ApplicationType.ApplicationType_Channel);\n                if(userId != null) {\n                    OutputApplicationUserInfo outputVerifyApplicationUser = new OutputApplicationUserInfo();\n                    outputVerifyApplicationUser.setUserId(userId);\n                    WFCMessage.User user = messagesStore.getUserInfo(userId);\n                    if(user != null) {\n                        outputVerifyApplicationUser.setDisplayName(user.getDisplayName());\n                        outputVerifyApplicationUser.setPortraitUrl(user.getPortrait());\n                    }\n                    result = RestResult.ok(outputVerifyApplicationUser);\n                } else {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_APPLICATION_TOKEN_ERROR_OR_TIMEOUT);\n                }\n            }\n\n            response.setStatus(HttpResponseStatus.OK);\n            response.setContent(gson.toJson(result));\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/channel/ChannelAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.channel;\n\nimport cn.wildfirechat.common.IMExceptionEvent;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.action.Action;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.ServerAPIHelper;\nimport io.moquette.spi.impl.Utils;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport cn.wildfirechat.common.ErrorCode;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.RateLimiter;\nimport win.liyufan.im.Utility;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.concurrent.Executor;\n\nabstract public class ChannelAction extends Action {\n    private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(ChannelAction.class);\n    protected WFCMessage.ChannelInfo channelInfo;\n\n    protected interface Callback {\n        void onSuccess(byte[] response);\n    }\n\n    @Override\n    public ErrorCode preAction(Request request, Response response) {\n        String nonce = request.getHeader(\"nonce\");\n        if (StringUtil.isNullOrEmpty(nonce)) {\n            nonce = request.getHeader(\"Nonce\");\n        }\n        String timestamp = request.getHeader(\"timestamp\");\n        if (StringUtil.isNullOrEmpty(timestamp)) {\n            timestamp = request.getHeader(\"Timestamp\");\n        }\n        String sign = request.getHeader(\"sign\");\n        if (StringUtil.isNullOrEmpty(sign)) {\n            sign = request.getHeader(\"Sign\");\n        }\n        String cid = request.getHeader(\"cid\");\n        if (StringUtil.isNullOrEmpty(cid)) {\n            cid = request.getHeader(\"Cid\");\n        }\n\n        if (StringUtil.isNullOrEmpty(nonce) || StringUtil.isNullOrEmpty(timestamp) || StringUtil.isNullOrEmpty(sign) || StringUtil.isNullOrEmpty(cid)) {\n            return ErrorCode.ERROR_CODE_API_NOT_SIGNED;\n        }\n\n        if (!channelLimiter.isGranted(cid)) {\n            return ErrorCode.ERROR_CODE_OVER_FREQUENCY;\n        }\n\n        Long ts;\n        try {\n            ts = Long.parseLong(timestamp);\n        } catch (Exception e) {\n            LOG.error(\"Channel timestamp:{} invalid\", timestamp);\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, IMExceptionEvent.EventType.CHANNEL_API_Exception);\n            return ErrorCode.ERROR_CODE_API_NOT_SIGNED;\n        }\n\n        if (System.currentTimeMillis() - ts > 2 * 60 * 60 * 1000) {\n            return ErrorCode.ERROR_CODE_SIGN_EXPIRED;\n        }\n\n        channelInfo = messagesStore.getChannelInfo(cid);\n        if (channelInfo == null) {\n            return ErrorCode.ERROR_CODE_CHANNEL_NO_EXIST;\n        }\n        \n        if (StringUtil.isNullOrEmpty(channelInfo.getSecret())) {\n            return ErrorCode.ERROR_CODE_CHANNEL_NO_SECRET;\n        }\n\n        String str = nonce + \"|\" + channelInfo.getSecret() + \"|\" + timestamp;\n        String localSign = DigestUtils.sha1Hex(str);\n        return localSign.equals(sign) ? ErrorCode.ERROR_CODE_SUCCESS : ErrorCode.ERROR_CODE_AUTH_FAILURE;\n    }\n\n    protected void sendResponse(Response response, ErrorCode errorCode, Object data) {\n        response.setStatus(HttpResponseStatus.OK);\n        if (errorCode == null) {\n            errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n        }\n\n        RestResult result = RestResult.resultOf(errorCode, errorCode.getMsg(), data);\n        response.setContent(gson.toJson(result));\n        response.send();\n    }\n\n    protected void sendApiMessage(Response response, String topic, byte[] message, Callback callback) {\n        sendApiMessage(response, channelInfo.getOwner(), topic, message, callback);\n    }\n    protected void sendApiMessage(Response response, String user, String topic, byte[] message, Callback callback) {\n        ServerAPIHelper.sendRequest(user, null, topic, message, new ServerAPIHelper.Callback() {\n            @Override\n            public void onSuccess(byte[] response) {\n                callback.onSuccess(response);\n            }\n            @Override\n            public void onError(ErrorCode errorCode) {\n                sendResponse(response, errorCode, null);\n            }\n\n            @Override\n            public void onTimeout() {\n                sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);\n            }\n\n            @Override\n            public Executor getResponseExecutor() {\n                return command -> {\n                    ctx.executor().execute(command);\n                };\n            }\n        }, ProtoConstants.RequestSourceType.Request_From_Channel);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/channel/GetChannelAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.channel;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.OutputGetChannelInfo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Channel_Get_Profile)\n@HttpMethod(\"POST\")\npublic class GetChannelAction extends ChannelAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            setResponseContent(RestResult.ok(OutputGetChannelInfo.fromPbInfo(channelInfo)), response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/channel/GetChannelSubscribersAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.channel;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.OutputStringList;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\n\n@Route(APIPath.Channel_Subscriber_List)\n@HttpMethod(\"POST\")\npublic class GetChannelSubscribersAction extends ChannelAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            OutputStringList outputStringList = new OutputStringList();\n            outputStringList.setList(new ArrayList<>());\n            outputStringList.getList().addAll(messagesStore.getChannelSubscriber(channelInfo.getTargetId()));\n            setResponseContent(RestResult.ok(outputStringList), response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/channel/GetIsChannelSubscriberAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.channel;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.InputChannelSubscribe;\nimport cn.wildfirechat.pojos.InputUserId;\nimport cn.wildfirechat.pojos.OutputStringList;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\n\nimport java.util.ArrayList;\n\n@Route(APIPath.Channel_Is_Subscriber)\n@HttpMethod(\"POST\")\npublic class GetIsChannelSubscriberAction extends ChannelAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputUserId input = getRequestBody(request.getNettyRequest(), InputUserId.class);\n            boolean isSubscriber = messagesStore.checkUserInChannel(input.getUserId(), channelInfo.getTargetId());\n            setResponseContent(RestResult.ok(isSubscriber), response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/channel/GetUserAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.channel;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Channel_User_Info)\n@HttpMethod(\"POST\")\npublic class GetUserAction extends ChannelAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetUserInfo inputUserId = getRequestBody(request.getNettyRequest(), InputGetUserInfo.class);\n            if (inputUserId != null\n                && (!StringUtil.isNullOrEmpty(inputUserId.getUserId()) || !StringUtil.isNullOrEmpty(inputUserId.getName()) || !StringUtil.isNullOrEmpty(inputUserId.getMobile()))) {\n\n                WFCMessage.User user = null;\n                if(!StringUtil.isNullOrEmpty(inputUserId.getUserId())) {\n                    user = messagesStore.getUserInfo(inputUserId.getUserId());\n                } else if(!StringUtil.isNullOrEmpty(inputUserId.getName())) {\n                    user = messagesStore.getUserInfoByName(inputUserId.getName());\n                } else if(!StringUtil.isNullOrEmpty(inputUserId.getMobile())) {\n                    user = messagesStore.getUserInfoByMobile(inputUserId.getMobile());\n                }\n\n                RestResult result;\n\n                if (user == null || StringUtil.isNullOrEmpty(user.getName()) || user.getDeleted() > 0) {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                } else {\n                    if (channelInfo.getOwner().equals(inputUserId.getUserId()) ||\n                            messagesStore.checkUserInChannel(user.getUid(), channelInfo.getTargetId())) {\n                        if((channelInfo.getStatus() & ProtoConstants.ChannelState.Channel_State_Mask_FullInfo) > 0) {\n                            result = RestResult.ok(InputOutputUserInfo.fromPbUser(user));\n                        } else {\n                            WFCMessage.User outUser = WFCMessage.User.newBuilder().setUid(user.getUid()).setName(user.getName()).setPortrait(user.getPortrait()).setDisplayName(user.getDisplayName()).build();\n                            result = RestResult.ok(InputOutputUserInfo.fromPbUser(outUser));\n                        }\n                    } else {\n                        if((channelInfo.getStatus() & ProtoConstants.ChannelState.Channel_State_Mask_Unsubscribed_User_Access) > 0) {\n                            WFCMessage.User outUser = WFCMessage.User.newBuilder().setUid(user.getUid()).setName(user.getName()).setPortrait(user.getPortrait()).setDisplayName(user.getDisplayName()).build();\n                            result = RestResult.ok(InputOutputUserInfo.fromPbUser(outUser));\n                        } else {\n                            result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_RIGHT);\n                        }\n                    }\n                }\n\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/channel/ModifyChannelProfileAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.channel;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputModifyChannelInfo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Channel_Update_Profile)\n@HttpMethod(\"POST\")\npublic class ModifyChannelProfileAction extends ChannelAction {\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputModifyChannelInfo input = getRequestBody(request.getNettyRequest(), InputModifyChannelInfo.class);\n            if (input != null) {\n                WFCMessage.ModifyChannelInfo modifyChannelInfo = WFCMessage.ModifyChannelInfo.newBuilder().setChannelId(channelInfo.getTargetId()).setType(input.getType()).setValue(input.getValue()).build();\n                sendApiMessage(response, IMTopic.ModifyChannelInfoTopic, modifyChannelInfo.toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        sendResponse(response, null, null);\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/channel/SendMessageAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.channel;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.SendChannelMessageData;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.Conversation;\nimport cn.wildfirechat.pojos.SendMessageData;\nimport cn.wildfirechat.pojos.SendMessageResult;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.proto.ProtoConstants.ConversationType.ConversationType_Channel;\n\n@Route(APIPath.Channel_Message_Send)\n@HttpMethod(\"POST\")\npublic class SendMessageAction extends ChannelAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            SendChannelMessageData sendChannelMessageData = getRequestBody(request.getNettyRequest(), SendChannelMessageData.class);\n            if(sendChannelMessageData.getTargets() != null && !sendChannelMessageData.getTargets().isEmpty()) {\n                if((channelInfo.getStatus() & ProtoConstants.ChannelState.Channel_State_Mask_Message_Unsubscribed) == 0 && (channelInfo.getStatus() & ProtoConstants.ChannelState.Channel_State_Mask_Global) == 0) {\n                    for (String target:sendChannelMessageData.getTargets()) {\n                        if(!messagesStore.checkUserInChannel(target, channelInfo.getTargetId())) {\n                            setResponseContent(RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_RIGHT, \"User \" + target + \" not in channel\"), response);\n                            return true;\n                        }\n                    }\n                }\n            }\n\n            SendMessageData sendMessageData = new SendMessageData();\n            sendMessageData.setConv(new Conversation());\n            sendMessageData.getConv().setType(ConversationType_Channel);\n            sendMessageData.getConv().setTarget(channelInfo.getTargetId());\n            sendMessageData.getConv().setLine(sendChannelMessageData.getLine());\n            sendMessageData.setSender(channelInfo.getOwner());\n            sendMessageData.setPayload(sendChannelMessageData.getPayload());\n            sendMessageData.setToUsers(sendChannelMessageData.getTargets());\n            if (SendMessageData.isValide(sendMessageData)) {\n                sendApiMessage(response, IMTopic.SendMessageTopic, sendMessageData.toProtoMessage().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        long messageId = byteBuf.readLong();\n                        long timestamp = byteBuf.readLong();\n                        sendResponse(response, null, new SendMessageResult(messageId, timestamp));\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/channel/SubscriberChannelAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.channel;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputChannelSubscribe;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Channel_Subscribe)\n@HttpMethod(\"POST\")\npublic class SubscriberChannelAction extends ChannelAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputChannelSubscribe input = getRequestBody(request.getNettyRequest(), InputChannelSubscribe.class);\n            if (input != null && !StringUtil.isNullOrEmpty(input.getTarget())) {\n                if(input.getSubscribe() > 0 && (channelInfo.getStatus() & ProtoConstants.ChannelState.Channel_State_Mask_Active_Subscribe) == 0) {\n                    response.setStatus(HttpResponseStatus.OK);\n                    RestResult result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_RIGHT);\n                    response.setContent(gson.toJson(result));\n                    return true;\n                }\n                WFCMessage.ListenChannel listenChannel = WFCMessage.ListenChannel.newBuilder().setChannelId(channelInfo.getTargetId()).setListen(input.getSubscribe()).build();\n                sendApiMessage(response, input.getTarget(), IMTopic.ChannelListenTopic, listenChannel.toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        sendResponse(response, null, null);\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/AddGroupMemberAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputAddGroupMember;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Robot_Group_Member_Add)\n@HttpMethod(\"POST\")\npublic class AddGroupMemberAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputAddGroupMember inputAddGroupMember = getRequestBody(request.getNettyRequest(), InputAddGroupMember.class);\n            inputAddGroupMember.setOperator(robot.getUid());\n            if (inputAddGroupMember.isValide()) {\n                sendApiRequest(response, IMTopic.AddGroupMemberTopic, inputAddGroupMember.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        sendResponse(response, null, null);\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/ApplicationGetUserInfoAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputApplicationGetUserInfo;\nimport cn.wildfirechat.pojos.OutputApplicationUserInfo;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Robot_Application_Get_UserInfo)\n@HttpMethod(\"POST\")\npublic class ApplicationGetUserInfoAction extends RobotAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputApplicationGetUserInfo inputUserToken = getRequestBody(request.getNettyRequest(), InputApplicationGetUserInfo.class);\n            RestResult result;\n            if (inputUserToken == null || StringUtil.isNullOrEmpty(inputUserToken.getAuthCode())) {\n                result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);\n            } else {\n                String userId = messagesStore.verifyApplicationAuthCode(inputUserToken.getAuthCode(), robot.getUid(), ProtoConstants.ApplicationType.ApplicationType_Robot);\n                if(userId != null) {\n                    OutputApplicationUserInfo outputVerifyApplicationUser = new OutputApplicationUserInfo();\n                    outputVerifyApplicationUser.setUserId(userId);\n                    WFCMessage.User user = messagesStore.getUserInfo(userId);\n                    if(user != null) {\n                        outputVerifyApplicationUser.setDisplayName(user.getDisplayName());\n                        outputVerifyApplicationUser.setPortraitUrl(user.getPortrait());\n                    }\n                    result = RestResult.ok(outputVerifyApplicationUser);\n                } else {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_APPLICATION_TOKEN_ERROR_OR_TIMEOUT);\n                }\n            }\n\n            response.setStatus(HttpResponseStatus.OK);\n            response.setContent(gson.toJson(result));\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/CreateGroupAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputCreateGroup;\nimport cn.wildfirechat.pojos.OutputCreateGroupResult;\nimport cn.wildfirechat.pojos.PojoGroupInfo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Robot_Create_Group)\n@HttpMethod(\"POST\")\npublic class CreateGroupAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputCreateGroup inputCreateGroup = getRequestBody(request.getNettyRequest(), InputCreateGroup.class);\n            inputCreateGroup.setOperator(robot.getUid());\n            inputCreateGroup.getGroup().getGroup_info().setOwner(robot.getUid());\n            if (inputCreateGroup.isValide()) {\n                PojoGroupInfo group_info = inputCreateGroup.getGroup().getGroup_info();\n                WFCMessage.CreateGroupRequest createGroupRequest = inputCreateGroup.toProtoGroupRequest();\n                sendApiRequest(response, IMTopic.CreateGroupTopic, createGroupRequest.toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        byte[] data = new byte[byteBuf.readableBytes()];\n                        byteBuf.readBytes(data);\n                        String groupId = new String(data);\n                        sendResponse(response, null, new OutputCreateGroupResult(groupId));\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/DeleteCallbackAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.RobotCallbackPojo;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Robot_Delete_Callback)\n@HttpMethod(\"POST\")\npublic class DeleteCallbackAction extends RobotAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            if(!StringUtil.isNullOrEmpty(robot.getCallback())) {\n                robot = robot.toBuilder().clearCallback().setState(0).build();\n                messagesStore.addRobot(robot);\n            }\n            setResponseContent(RestResult.ok(), response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/DismissGroupAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputDismissGroup;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Robot_Group_Dismiss)\n@HttpMethod(\"POST\")\npublic class DismissGroupAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputDismissGroup inputDismissGroup = getRequestBody(request.getNettyRequest(), InputDismissGroup.class);\n            inputDismissGroup.setOperator(robot.getUid());\n            if (inputDismissGroup.isValide()) {\n                sendApiRequest(response, IMTopic.DismissGroupTopic, inputDismissGroup.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        sendResponse(response, null, null);\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/GetCallbackAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.RobotCallbackPojo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Robot_Get_Callback)\n@HttpMethod(\"POST\")\npublic class GetCallbackAction extends RobotAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            RobotCallbackPojo out = new RobotCallbackPojo();\n            out.setUrl(robot.getCallback());\n            setResponseContent(RestResult.ok(out), response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/GetGroupInfoAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetGroup;\nimport cn.wildfirechat.pojos.PojoGroupInfo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.action.admin.AdminAction;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Robot_Group_Get_Info)\n@HttpMethod(\"POST\")\npublic class GetGroupInfoAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetGroup inputGetGroup = getRequestBody(request.getNettyRequest(), InputGetGroup.class);\n            if (inputGetGroup != null\n                && (!StringUtil.isNullOrEmpty(inputGetGroup.getGroupId()))) {\n\n                WFCMessage.GroupInfo groupInfo = messagesStore.getGroupInfo(inputGetGroup.getGroupId());\n                RestResult result;\n                if (groupInfo == null) {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                } else {\n                    PojoGroupInfo pojoGroupInfo = new PojoGroupInfo();\n                    pojoGroupInfo.setExtra(groupInfo.getExtra());\n                    pojoGroupInfo.setName(groupInfo.getName());\n                    pojoGroupInfo.setOwner(groupInfo.getOwner());\n                    pojoGroupInfo.setPortrait(groupInfo.getPortrait());\n                    pojoGroupInfo.setTarget_id(groupInfo.getTargetId());\n                    pojoGroupInfo.setType(groupInfo.getType());\n                    pojoGroupInfo.setMember_count(groupInfo.getMemberCount());\n                    pojoGroupInfo.setMute(groupInfo.getMute());\n                    pojoGroupInfo.setJoin_type(groupInfo.getJoinType());\n                    pojoGroupInfo.setPrivate_chat(groupInfo.getPrivateChat());\n                    pojoGroupInfo.setSearchable(groupInfo.getSearchable());\n                    pojoGroupInfo.setMax_member_count(groupInfo.getMemberCount());\n                    pojoGroupInfo.setHistory_message(groupInfo.getHistoryMessage());\n                    pojoGroupInfo.setSuper_group(groupInfo.getSuperGroup()>0);\n                    pojoGroupInfo.setDeleted(groupInfo.getDeleted()>0);\n                    pojoGroupInfo.setUpdate_dt(groupInfo.getUpdateDt());\n                    pojoGroupInfo.setMember_update_dt(groupInfo.getMemberUpdateDt());\n                    result = RestResult.ok(pojoGroupInfo);\n                }\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/GetGroupMemberAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetGroup;\nimport cn.wildfirechat.pojos.InputGetGroupMember;\nimport cn.wildfirechat.pojos.OutputGroupMemberList;\nimport cn.wildfirechat.pojos.PojoGroupMember;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Route(APIPath.Robot_Group_Member_Get)\n@HttpMethod(\"POST\")\npublic class GetGroupMemberAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetGroupMember input = getRequestBody(request.getNettyRequest(), InputGetGroupMember.class);\n            String robotId = robot.getUid();\n            if (input != null\n                && (!StringUtil.isNullOrEmpty(input.getGroupId()))\n                && (!StringUtil.isNullOrEmpty(input.getMemberId()))) {\n\n                List<WFCMessage.GroupMember> members = new ArrayList<>();\n                ErrorCode errorCode = messagesStore.getGroupMembers(null, input.getGroupId(), 0, members);\n                RestResult result;\n                if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                    result = RestResult.resultOf(errorCode);\n                } else {\n                    WFCMessage.GroupMember groupMember = null;\n                    boolean isInGroup = false;\n                    for (WFCMessage.GroupMember member : members) {\n                        if (member.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Removed) {\n                            continue;\n                        }\n                        if(member.getMemberId().equals(robotId)) {\n                            isInGroup = true;\n                            if(groupMember != null) {\n                                break;\n                            }\n                        }\n                        if(member.getMemberId().equals(input.getMemberId())) {\n                            groupMember = member;\n                            if(isInGroup) {\n                                break;\n                            }\n                        }\n                    }\n                    if(!isInGroup) {\n                        result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_IN_GROUP);\n                    } else {\n                        if(groupMember == null) {\n                            result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                        } else {\n                            PojoGroupMember pm = new PojoGroupMember();\n                            pm.setMember_id(groupMember.getMemberId());\n                            pm.setAlias(groupMember.getAlias());\n                            pm.setType(groupMember.getType());\n                            pm.setExtra(groupMember.getExtra());\n                            pm.setCreateDt(groupMember.getCreateDt());\n                            result = RestResult.ok(pm);\n                        }\n                    }\n                }\n\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/GetGroupMembersAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetGroup;\nimport cn.wildfirechat.pojos.OutputGroupMemberList;\nimport cn.wildfirechat.pojos.PojoGroupMember;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.action.admin.AdminAction;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Route(APIPath.Robot_Group_Member_List)\n@HttpMethod(\"POST\")\npublic class GetGroupMembersAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetGroup inputGetGroup = getRequestBody(request.getNettyRequest(), InputGetGroup.class);\n            String robotId = robot.getUid();\n            if (inputGetGroup != null\n                && (!StringUtil.isNullOrEmpty(inputGetGroup.getGroupId()))) {\n\n                List<WFCMessage.GroupMember> members = new ArrayList<>();\n                ErrorCode errorCode = messagesStore.getGroupMembers(null, inputGetGroup.getGroupId(), 0, members);\n                RestResult result;\n                if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                    result = RestResult.resultOf(errorCode);\n                } else {\n                    OutputGroupMemberList out = new OutputGroupMemberList();\n                    out.setMembers(new ArrayList<>());\n                    boolean isInGroup = false;\n                    for (WFCMessage.GroupMember member : members) {\n                        if (member.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Removed) {\n                            continue;\n                        }\n                        if(member.getMemberId().equals(robotId)) {\n                            isInGroup = true;\n                        }\n                        PojoGroupMember pm = new PojoGroupMember();\n                        pm.setMember_id(member.getMemberId());\n                        pm.setAlias(member.getAlias());\n                        pm.setType(member.getType());\n                        pm.setExtra(member.getExtra());\n                        pm.setCreateDt(member.getCreateDt());\n                        out.getMembers().add(pm);\n                    }\n                    if(!isInGroup) {\n                        out.getMembers().clear();\n                    }\n                    result = RestResult.ok(out);\n                }\n\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/GetProfileAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.OutputRobot;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Robot_Get_Profile)\n@HttpMethod(\"POST\")\npublic class GetProfileAction extends RobotAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            WFCMessage.User user = messagesStore.getUserInfo(robot.getUid());\n            RestResult result;\n            if (user == null) {\n                result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n            } else {\n                OutputRobot outputRobot = new OutputRobot();\n                outputRobot.fromUser(user);\n                outputRobot.fromRobot(robot, false);\n                result = RestResult.ok(outputRobot);\n            }\n            setResponseContent(result, response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/GetUploadUrlAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetPresignedUploadUrl;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.OutputPresignedUploadUrl;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.qiniu.util.Auth;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.moquette.server.config.MediaServerConfig;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\n\nimport javax.crypto.Mac;\nimport javax.crypto.spec.SecretKeySpec;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLEncoder;\nimport java.nio.charset.StandardCharsets;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.time.ZonedDateTime;\nimport java.util.*;\n\n@Route(APIPath.Robot_Get_Presigned_Upload_Url)\n@HttpMethod(\"POST\")\npublic class GetUploadUrlAction extends RobotAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            if(!MediaServerConfig.USER_QINIU) {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n                return true;\n            }\n\n            InputGetPresignedUploadUrl inputUserId = getRequestBody(request.getNettyRequest(), InputGetPresignedUploadUrl.class);\n\n            if (StringUtil.isNullOrEmpty(inputUserId.contentType)) {\n                inputUserId.contentType = \"application/octet-stream\";\n            }\n            String uuid = UUID.randomUUID().toString().replace(\"-\", \"\");\n            inputUserId.fileName = uuid + inputUserId.fileName;\n\n            int type = inputUserId.mediaType;\n            String bucketName;\n            String bucketDomain;\n            switch (type) {\n                case 0:\n                default:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_GENERAL_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN;\n                    break;\n                case 1:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_IMAGE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_IMAGE_DOMAIN;\n                    break;\n                case 2:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_VOICE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_VOICE_DOMAIN;\n                    break;\n                case 3:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_VIDEO_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_VIDEO_DOMAIN;\n                    break;\n                case 4:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_FILE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_FILE_DOMAIN;\n                    break;\n                case 5:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_PORTRAIT_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_PORTRAIT_DOMAIN;\n                    break;\n                case 6:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_FAVORITE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_FAVORITE_DOMAIN;\n                    break;\n                case 7:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_STICKER_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_STICKER_DOMAIN;\n                    break;\n                case 8:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_MOMENTS_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_MOMENTS_DOMAIN;\n                    break;\n                case 9:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_CUSTOM1_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_CUSTOM1_DOMAIN;\n                    break;\n                case 10:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_CUSTOM2_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_CUSTOM2_DOMAIN;\n                    break;\n                case 11:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_CUSTOM3_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_CUSTOM3_DOMAIN;\n                    break;\n                case 12:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_PAN_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_PAN_DOMAIN;\n                    break;\n            }\n\n            if(StringUtil.isNullOrEmpty(bucketName)) {\n                bucketName = MediaServerConfig.QINIU_BUCKET_GENERAL_NAME;\n                bucketDomain = MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN;\n            }\n\n            String key = inputUserId.fileName;\n            Auth auth = Auth.create(MediaServerConfig.QINIU_ACCESS_KEY, MediaServerConfig.QINIU_SECRET_KEY);\n            String token = auth.uploadToken(bucketName, key);\n            String downloadUrl = bucketDomain + \"/\" + key;\n            String uploadUrl = \"https://\" + MediaServerConfig.QINIU_SERVER_URL + \"?\" + token + \"?\" + key;\n\n            OutputPresignedUploadUrl outputPresignedUploadUrl = new OutputPresignedUploadUrl();\n            outputPresignedUploadUrl.uploadUrl = uploadUrl;\n            outputPresignedUploadUrl.downloadUrl = downloadUrl;\n            outputPresignedUploadUrl.type = 1;\n            setResponseContent(RestResult.ok(outputPresignedUploadUrl), response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/GetUserAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.InputGetUserInfo;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport cn.wildfirechat.common.ErrorCode;\n\n@Route(APIPath.Robot_User_Info)\n@HttpMethod(\"POST\")\npublic class GetUserAction extends RobotAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputGetUserInfo inputUserId = getRequestBody(request.getNettyRequest(), InputGetUserInfo.class);\n            if (inputUserId != null\n                && (!StringUtil.isNullOrEmpty(inputUserId.getUserId()) || !StringUtil.isNullOrEmpty(inputUserId.getName()) || !StringUtil.isNullOrEmpty(inputUserId.getMobile()))) {\n\n                WFCMessage.User user = null;\n                if(!StringUtil.isNullOrEmpty(inputUserId.getUserId())) {\n                    user = messagesStore.getUserInfo(inputUserId.getUserId());\n                } else if(!StringUtil.isNullOrEmpty(inputUserId.getName())) {\n                    user = messagesStore.getUserInfoByName(inputUserId.getName());\n                } else if(!StringUtil.isNullOrEmpty(inputUserId.getMobile())) {\n                    user = messagesStore.getUserInfoByMobile(inputUserId.getMobile());\n                }\n\n                RestResult result;\n                if (user == null || user.getDeleted() > 0) {\n                    result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);\n                } else {\n                    InputOutputUserInfo outputUserInfo = InputOutputUserInfo.fromPbUser(user);\n                    int mask = messagesStore.getRobotGetUserInfoMask();\n                    if((mask & 1) == 0) {\n                        outputUserInfo.setName(null);\n                    }\n                    if((mask & 2) == 0) {\n                        outputUserInfo.setMobile(null);\n                    }\n                    if((mask & 4) == 0) {\n                        outputUserInfo.setEmail(null);\n                    }\n                    if((mask & 8) == 0) {\n                        outputUserInfo.setAddress(null);\n                    }\n                    if((mask & 16) == 0) {\n                        outputUserInfo.setCompany(null);\n                    }\n                    if((mask & 32) == 0) {\n                        outputUserInfo.setExtra(null);\n                    }\n                    if((mask & 64) == 0) {\n                        outputUserInfo.setUpdateDt(0);\n                    }\n                    if((mask & 128) == 0) {\n                        outputUserInfo.setGender(0);\n                    }\n                    if((mask & 256) == 0) {\n                        outputUserInfo.setSocial(null);\n                    }\n                    if((mask & 512) == 0) {\n                        outputUserInfo.setType(0);\n                    }\n                    result = RestResult.ok(outputUserInfo);\n                }\n                setResponseContent(result, response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/KickoffGroupMemberAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputKickoffGroupMember;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Robot_Group_Member_Kickoff)\n@HttpMethod(\"POST\")\npublic class KickoffGroupMemberAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputKickoffGroupMember inputKickoffGroupMember = getRequestBody(request.getNettyRequest(), InputKickoffGroupMember.class);\n            inputKickoffGroupMember.setOperator(robot.getUid());\n            if (inputKickoffGroupMember.isValide()) {\n                sendApiRequest(response, IMTopic.KickoffGroupMemberTopic, inputKickoffGroupMember.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        sendResponse(response, null, null);\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/ModifyGroupInfoAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputModifyGroupInfo;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Robot_Group_Modify_Info)\n@HttpMethod(\"POST\")\npublic class ModifyGroupInfoAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputModifyGroupInfo inputAddGroupMember = getRequestBody(request.getNettyRequest(), InputModifyGroupInfo.class);\n            inputAddGroupMember.setOperator(robot.getUid());\n            if (inputAddGroupMember.isValide()) {\n                sendApiRequest(response, IMTopic.ModifyGroupInfoTopic, inputAddGroupMember.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        sendResponse(response, null, null);\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/ModifyGroupMemberAliasAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputSetGroupMemberAlias;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Robot_Group_Set_Member_Alias)\n@HttpMethod(\"POST\")\npublic class ModifyGroupMemberAliasAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputSetGroupMemberAlias inputSetGroupMemberAlias = getRequestBody(request.getNettyRequest(), InputSetGroupMemberAlias.class);\n            inputSetGroupMemberAlias.setOperator(robot.getUid());\n            if (inputSetGroupMemberAlias.isValide()) {\n                sendApiRequest(response, IMTopic.ModifyGroupMemberAliasTopic, inputSetGroupMemberAlias.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        sendResponse(response, null, null);\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/ModifyGroupMemberExtraAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputSetGroupMemberExtra;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Robot_Group_Set_Member_Extra)\n@HttpMethod(\"POST\")\npublic class ModifyGroupMemberExtraAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputSetGroupMemberExtra inputSetGroupMemberExtra = getRequestBody(request.getNettyRequest(), InputSetGroupMemberExtra.class);\n            inputSetGroupMemberExtra.setOperator(robot.getUid());\n            if (inputSetGroupMemberExtra.isValide()) {\n                sendApiRequest(response, IMTopic.ModifyGroupMemberExtraTopic, inputSetGroupMemberExtra.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        sendResponse(response, null, null);\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                response.setStatus(HttpResponseStatus.OK);\n                RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);\n                response.setContent(gson.toJson(result));\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/QuitGroupMemberAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputQuitGroup;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Robot_Group_Member_Quit)\n@HttpMethod(\"POST\")\npublic class QuitGroupMemberAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputQuitGroup inputQuitGroup = getRequestBody(request.getNettyRequest(), InputQuitGroup.class);\n            inputQuitGroup.setOperator(robot.getUid());\n            if (inputQuitGroup.isValide()) {\n                sendApiRequest(response, IMTopic.QuitGroupTopic, inputQuitGroup.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        sendResponse(response, null, null);\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/ReplyMessageAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.Conversation;\nimport cn.wildfirechat.pojos.ReplyMessageData;\nimport cn.wildfirechat.pojos.SendMessageData;\nimport cn.wildfirechat.pojos.SendMessageResult;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport org.jetbrains.annotations.NotNull;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.Arrays;\n\n@Route(APIPath.Robot_Message_Reply)\n@HttpMethod(\"POST\")\npublic class ReplyMessageAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            ReplyMessageData replyMessageData = getRequestBody(request.getNettyRequest(), ReplyMessageData.class);\n            if (ReplyMessageData.isValide(replyMessageData)) {\n                WFCMessage.Message message = messagesStore.getMessage(replyMessageData.getMessageUid());\n                ErrorCode errorCode = null;\n                if(message == null) {\n                    errorCode = ErrorCode.ERROR_CODE_NOT_EXIST;\n                } else if(!message.getContent().getMentionedTargetList().contains(robot.getUid())) {\n                    errorCode = ErrorCode.ERROR_CODE_INVALID_MESSAGE;\n                } else if(message.getConversation().getType() != ProtoConstants.ConversationType.ConversationType_Private && message.getConversation().getType() != ProtoConstants.ConversationType.ConversationType_Group) {\n                    errorCode = ErrorCode.ERROR_CODE_NOT_IMPLEMENT;\n                } else if(System.currentTimeMillis() - message.getServerTimestamp() > 15*60*1000) {\n                    errorCode = ErrorCode.ERROR_CODE_RECALL_TIME_EXPIRED;\n                } else if(!messagesStore.isRobotMentionExternalRobot()) {\n                    if(message.getConversation().getType() != ProtoConstants.ConversationType.ConversationType_Group) {\n                        errorCode = ErrorCode.ERROR_CODE_NOT_IMPLEMENT;\n                    } else {\n                        WFCMessage.GroupMember member = messagesStore.getGroupMember(message.getConversation().getTarget(), robot.getUid());\n                        if(member == null || member.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Removed) {\n                            errorCode = ErrorCode.ERROR_CODE_NOT_IMPLEMENT;\n                        }\n                    }\n                }\n\n                if(errorCode != null) {\n                    response.setStatus(HttpResponseStatus.OK);\n                    RestResult result = RestResult.resultOf(errorCode);\n                    response.setContent(gson.toJson(result));\n                    return true;\n                }\n\n                SendMessageData sendMessageData = getSendMessageData(message, replyMessageData);\n                WFCMessage.Message newMsg = sendMessageData.toProtoMessage().toBuilder().setMessageId(message.getMessageId()).build();\n                sendApiRequest(response, IMTopic.RobotReplyMessageTopic, newMsg.toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode ec = ErrorCode.fromCode(byteBuf.readByte());\n                    if (ec == ErrorCode.ERROR_CODE_SUCCESS) {\n                        long messageId = byteBuf.readLong();\n                        long timestamp = byteBuf.readLong();\n                        sendResponse(response, null, new SendMessageResult(messageId, timestamp));\n                    } else {\n                        sendResponse(response, ec, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n\n    private @NotNull SendMessageData getSendMessageData(WFCMessage.Message message, ReplyMessageData replyMessageData) {\n        SendMessageData sendMessageData = new SendMessageData();\n        sendMessageData.setSender(robot.getUid());\n        Conversation conversation = new Conversation();\n        conversation.setType(message.getConversation().getType());\n        conversation.setLine(message.getConversation().getLine());\n        conversation.setTarget(message.getConversation().getTarget());\n        sendMessageData.setConv(conversation);\n        sendMessageData.setPayload(replyMessageData.getPayload());\n        if(replyMessageData.isOnly2Sender()) {\n            sendMessageData.setToUsers(Arrays.asList(message.getFromUser()));\n        }\n        return sendMessageData;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/RobotAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\nimport cn.wildfirechat.common.IMExceptionEvent;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.action.Action;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.moquette.persistence.ServerAPIHelper;\nimport io.moquette.spi.impl.Utils;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport cn.wildfirechat.common.ErrorCode;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.RateLimiter;\nimport win.liyufan.im.Utility;\n\nimport java.io.UnsupportedEncodingException;\nimport java.util.concurrent.Executor;\n\nabstract public class RobotAction extends Action {\n    protected static final Logger LOG = LoggerFactory.getLogger(RobotAction.class);\n\n    protected WFCMessage.Robot robot;\n\n    protected interface Callback {\n        void onSuccess(byte[] response);\n    }\n\n    @Override\n    public ErrorCode preAction(Request request, Response response) {\n        String nonce = request.getHeader(\"nonce\");\n        if (StringUtil.isNullOrEmpty(nonce)) {\n            nonce = request.getHeader(\"Nonce\");\n        }\n        String timestamp = request.getHeader(\"timestamp\");\n        if (StringUtil.isNullOrEmpty(timestamp)) {\n            timestamp = request.getHeader(\"Timestamp\");\n        }\n        String sign = request.getHeader(\"sign\");\n        if (StringUtil.isNullOrEmpty(sign)) {\n            sign = request.getHeader(\"Sign\");\n        }\n        String rid = request.getHeader(\"rid\");\n        if (StringUtil.isNullOrEmpty(rid)) {\n            rid = request.getHeader(\"Rid\");\n        }\n\n        if (StringUtil.isNullOrEmpty(nonce) || StringUtil.isNullOrEmpty(timestamp) || StringUtil.isNullOrEmpty(sign) || StringUtil.isNullOrEmpty(rid)) {\n            return ErrorCode.ERROR_CODE_API_NOT_SIGNED;\n        }\n\n        if (!robotLimiter.isGranted(rid)) {\n            return ErrorCode.ERROR_CODE_OVER_FREQUENCY;\n        }\n\n        Long ts;\n        try {\n            ts = Long.parseLong(timestamp);\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, IMExceptionEvent.EventType.ROBOT_API_Exception);\n            return ErrorCode.ERROR_CODE_API_NOT_SIGNED;\n        }\n\n        if (System.currentTimeMillis() - ts > 2 * 60 * 60 * 1000) {\n            return ErrorCode.ERROR_CODE_SIGN_EXPIRED;\n        }\n\n        robot = messagesStore.getRobot(rid);\n        if (robot == null) {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n        if (StringUtil.isNullOrEmpty(robot.getSecret())) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        String str = nonce + \"|\" + robot.getSecret() + \"|\" + timestamp;\n        String localSign = DigestUtils.sha1Hex(str);\n        return localSign.equals(sign) ? ErrorCode.ERROR_CODE_SUCCESS : ErrorCode.ERROR_CODE_AUTH_FAILURE;\n    }\n\n    protected void sendResponse(Response response, ErrorCode errorCode, Object data) {\n        response.setStatus(HttpResponseStatus.OK);\n        if (errorCode == null) {\n            errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n        }\n\n        RestResult result = RestResult.resultOf(errorCode, errorCode.getMsg(), data);\n        response.setContent(gson.toJson(result));\n        response.send();\n    }\n\n    protected void sendApiRequest(Response response, String topic, byte[] message, Callback callback) {\n        ServerAPIHelper.sendRequest(robot.getUid(), null, topic, message, new ServerAPIHelper.Callback() {\n            @Override\n            public void onSuccess(byte[] response) {\n                callback.onSuccess(response);\n            }\n\n            @Override\n            public void onError(ErrorCode errorCode) {\n                sendResponse(response, errorCode, null);\n            }\n\n            @Override\n            public void onTimeout() {\n                sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);\n            }\n\n            @Override\n            public Executor getResponseExecutor() {\n                return command -> {\n                    ctx.executor().execute(command);\n                };\n            }\n        }, ProtoConstants.RequestSourceType.Request_From_Robot);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/SendMessageAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport cn.wildfirechat.pojos.SendMessageData;\nimport cn.wildfirechat.pojos.SendMessageResult;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Robot_Message_Send)\n@HttpMethod(\"POST\")\npublic class SendMessageAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            SendMessageData sendMessageData = getRequestBody(request.getNettyRequest(), SendMessageData.class);\n            sendMessageData.setSender(robot.getUid());\n            if (SendMessageData.isValide(sendMessageData)) {\n                sendApiRequest(response, IMTopic.SendMessageTopic, sendMessageData.toProtoMessage().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        long messageId = byteBuf.readLong();\n                        long timestamp = byteBuf.readLong();\n                        sendResponse(response, null, new SendMessageResult(messageId, timestamp));\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/SetCallbackAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputGetGroup;\nimport cn.wildfirechat.pojos.RobotCallbackPojo;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\n\n@Route(APIPath.Robot_Set_Callback)\n@HttpMethod(\"POST\")\npublic class SetCallbackAction extends RobotAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            RobotCallbackPojo input = getRequestBody(request.getNettyRequest(), RobotCallbackPojo.class);\n            if(!StringUtil.isNullOrEmpty(input.getUrl())) {\n                if(!input.getUrl().equals(robot.getCallback()) && robot.getState() != 1) {\n                    robot = robot.toBuilder().setCallback(input.getUrl()).setState(1).build();\n                    messagesStore.addRobot(robot);\n                }\n                setResponseContent(RestResult.ok(), response);\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/TransferGroupAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.InputTransferGroup;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport win.liyufan.im.IMTopic;\n\n@Route(APIPath.Robot_Group_Transfer)\n@HttpMethod(\"POST\")\npublic class TransferGroupAction extends RobotAction {\n\n    @Override\n    public boolean isTransactionAction() {\n        return true;\n    }\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            InputTransferGroup inputDismissGroup = getRequestBody(request.getNettyRequest(), InputTransferGroup.class);\n            inputDismissGroup.setOperator(robot.getUid());\n            if (inputDismissGroup.isValide()) {\n                sendApiRequest(response, IMTopic.TransferGroupTopic, inputDismissGroup.toProtoGroupRequest().toByteArray(), result -> {\n                    ByteBuf byteBuf = Unpooled.buffer();\n                    byteBuf.writeBytes(result);\n                    ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());\n                    if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                        sendResponse(response, null, null);\n                    } else {\n                        sendResponse(response, errorCode, null);\n                    }\n                });\n                return false;\n            } else {\n                setResponseContent(RestResult.resultOf(ErrorCode.INVALID_PARAMETER), response);\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/action/robot/UpdateProfileAction.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.action.robot;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.IntStringPairPojo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.annotation.HttpMethod;\nimport com.xiaoleilu.loServer.annotation.Route;\nimport com.xiaoleilu.loServer.handler.Request;\nimport com.xiaoleilu.loServer.handler.Response;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\n\nimport static cn.wildfirechat.pojos.MyInfoType.*;\n\n@Route(APIPath.Robot_Update_Profile)\n@HttpMethod(\"POST\")\npublic class UpdateProfileAction extends RobotAction {\n\n    @Override\n    public boolean action(Request request, Response response) {\n        if (request.getNettyRequest() instanceof FullHttpRequest) {\n            IntStringPairPojo input = getRequestBody(request.getNettyRequest(), IntStringPairPojo.class);\n\n            WFCMessage.User.Builder builder = messagesStore.getUserInfo(robot.getUid()).toBuilder();\n            boolean modified = false;\n            String value = input.getStrValue() == null ? \"\" : input.getStrValue();\n            switch (input.getIntValue()) {\n                case Modify_DisplayName:\n                    builder.setDisplayName(value);\n                    modified = true;\n                    break;\n                case Modify_Gender:\n                    builder.setGender(Integer.parseInt(value));\n                    modified = true;\n                    break;\n                case Modify_Portrait:\n                    builder.setPortrait(value);\n                    modified = true;\n                    break;\n                //不允许修改电话号码，如果修改电话号码必须通过admin进行修改\n//              case Modify_Mobile:\n//                    builder.setMobile(value);\n//                    modified = true;\n//                    break;\n                case Modify_Email:\n                    builder.setEmail(value);\n                    modified = true;\n                    break;\n                case Modify_Address:\n                    builder.setAddress(value);\n                    modified = true;\n                    break;\n                case Modify_Company:\n                    builder.setCompany(value);\n                    modified = true;\n                    break;\n                case Modify_Social:\n                    builder.setSocial(value);\n                    modified = true;\n                    break;\n                case Modify_Extra:\n                    builder.setExtra(value);\n                    modified = true;\n                    break;\n                default:\n                    break;\n            }\n\n            RestResult result = RestResult.ok();\n            if(modified) {\n                try {\n                    builder.setUpdateDt(System.currentTimeMillis());\n                    messagesStore.updateUserInfo(builder.build());\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    result.setErrorCode(ErrorCode.ERROR_CODE_SERVER_ERROR);\n                }\n            }\n            setResponseContent(result, response);\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/annotation/HttpMethod.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.annotation;\n\n\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n@Retention(RetentionPolicy.RUNTIME)/*保留的时间长短*/\n@Inherited/*只用于class，可被子类继承*/\npublic @interface HttpMethod {\n    String value() default \"GET\";\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/annotation/RequireAuthentication.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.annotation;\n\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n@Retention(RetentionPolicy.RUNTIME)/*保留的时间长短*/\n@Inherited/*只用于class，可被子类继承*/\npublic @interface RequireAuthentication {\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/annotation/Route.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.annotation;\n\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/**\n * 注解，用于自定义访问的URL路径<br>\n * 值可以是一个请求路径，如果需要指定HTTP方法，在前面加方法名用\":\"分隔既可<br>\n * @author loolly\n *\n */\n@Retention(RetentionPolicy.RUNTIME)/*保留的时间长短*/\n@Inherited/*只用于class，可被子类继承*/\npublic @interface Route {\n\tString value();\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/exception/ServerSettingException.java",
    "content": "package com.xiaoleilu.loServer.exception;\n\n\nimport cn.hutool.core.util.StrUtil;\n\n/**\n * 设置异常\n * @author xiaoleilu\n */\npublic class ServerSettingException extends RuntimeException{\n\tprivate static final long serialVersionUID = -4134588858314744501L;\n\n\tpublic ServerSettingException(Throwable e) {\n\t\tsuper(e);\n\t}\n\t\n\tpublic ServerSettingException(String message) {\n\t\tsuper(message);\n\t}\n\t\n\tpublic ServerSettingException(String messageTemplate, Object... params) {\n\t\tsuper(StrUtil.format(messageTemplate, params));\n\t}\n\t\n\tpublic ServerSettingException(String message, Throwable throwable) {\n\t\tsuper(message, throwable);\n\t}\n\t\n\tpublic ServerSettingException(Throwable throwable, String messageTemplate, Object... params) {\n\t\tsuper(StrUtil.format(messageTemplate, params), throwable);\n\t}\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/filter/Filter.java",
    "content": "package com.xiaoleilu.loServer.filter;\r\n\r\nimport com.xiaoleilu.loServer.handler.Request;\r\nimport com.xiaoleilu.loServer.handler.Response;\r\n\r\n/**\r\n * 过滤器接口<br>\r\n * @author Looly\r\n *\r\n */\r\npublic interface Filter {\r\n\t\r\n\t/**\r\n\t * 执行过滤\r\n\t * @param request 请求对象\r\n\t * @param response 响应对象\r\n\t * @return 如果返回true，则继续执行下一步内容，否则中断\r\n\t */\r\n\tpublic boolean doFilter(Request request, Response response);\r\n}\r\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/handler/ActionHandler.java",
    "content": "package com.xiaoleilu.loServer.handler;\n\nimport cn.hutool.core.lang.Singleton;\nimport cn.wildfirechat.common.IMExceptionEvent;\nimport com.xiaoleilu.loServer.ServerSetting;\nimport com.xiaoleilu.loServer.action.Action;\nimport com.xiaoleilu.loServer.action.UnknownErrorAction;\nimport com.xiaoleilu.loServer.action.FileAction;\nimport com.xiaoleilu.loServer.filter.Filter;\n\nimport io.moquette.spi.IMessagesStore;\nimport io.moquette.spi.ISessionsStore;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.util.internal.StringUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.Utility;\n\n/**\n * Action处理单元\n *\n * @author Looly\n */\nabstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttpRequest> {\n    private static final Logger Logger = LoggerFactory.getLogger(ActionHandler.class);\n\n    public ActionHandler(IMessagesStore messagesStore, ISessionsStore sessionsStore) {\n        Action.messagesStore = messagesStore;\n        Action.sessionsStore = sessionsStore;\n    }\n\n    @Override\n\tprotected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) throws Exception {\n\t\tfinal Request request = Request.build(ctx, fullHttpRequest);\n\t\tfinal Response response = Response.build(ctx, request);\n\n\t\tresponse.setContentType(\"application/json\");\n\t\ttry {\n\t\t\t//do filter\n\t\t\tboolean isPass = this.doFilter(request, response);\n\n\t\t\tif(isPass){\n\t\t\t\t//do action\n\t\t\t\tthis.doAction(ctx, request, response);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t    e.printStackTrace();\n            Utility.printExecption(Logger, e, IMExceptionEvent.EventType.SHORT_LINK_Exception);\n\t\t\tAction errorAction = ServerSetting.getErrorAction(ServerSetting.MAPPING_ERROR);\n\t\t\trequest.putParam(UnknownErrorAction.ERROR_PARAM_NAME, e);\n\t\t\tresponse.setContent(e.toString());\n\t\t\terrorAction.doAction(request, response);\n\n            //如果发送请求未被触发，则触发之，否则跳过。\n            if(!response.isSent()){\n                response.send();\n            }\n\n            ctx.fireExceptionCaught(e);\n            ctx.close();\n\t\t}\n\n\n\t}\n\n\t@Override\n\tpublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\n        super.exceptionCaught(ctx, cause);\n        Logger.warn(\"{}\", cause.getMessage());\n        Channel channel = ctx.channel();\n        if(channel.isActive())ctx.close();\n\t}\n\n\t//---------------------------------------------------------------------------------------- Private method start\n\t/**\n\t * 执行过滤\n\t * @param request 请求\n\t * @param response 响应\n\t * @@return  是否继续\n\t */\n\tprivate boolean doFilter(Request request, Response response) {\n\t\t//全局过滤器\n\t\tFilter filter = ServerSetting.getFilter(ServerSetting.MAPPING_ALL);\n\t\tif(null != filter){\n\t\t\tif(false == filter.doFilter(request, response)){\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t//自定义Path过滤器\n\t\tfilter = ServerSetting.getFilter(request.getPath());\n\t\tif(null != filter){\n\t\t\tif(false == filter.doFilter(request, response)){\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tabstract boolean isValidePath(String path);\n\t/**\n\t * 执行Action\n\t * @param request 请求对象\n\t * @param response 响应对象\n\t */\n\tprivate void doAction(ChannelHandlerContext ctx, Request request, Response response){\n\t    if((\"/route\".equalsIgnoreCase(request.getPath()) || (!StringUtil.isNullOrEmpty(request.getPath()) && request.getPath().startsWith(\"/fs/\")))\n            && \"OPTIONS\".equalsIgnoreCase(request.getMethod())){\n\t        handleOptions(ctx, request, response);\n\t        return;\n        }\n\n        if (\"HEAD\".equalsIgnoreCase(request.getMethod())) {\n            response.setStatus(HttpResponseStatus.OK);\n            response.send();\n            return;\n        }\n\n\t\tAction action;\n\t\tif (isValidePath(request.getPath())) {\n            action = ServerSetting.getAction(request.getPath(), request.getMethod().toUpperCase());\n            if (action != null) {\n                Logger.info(\"Http request whit url {}\", request.getPath());\n            }\n        } else {\n            action = ServerSetting.getErrorAction(ServerSetting.MAPPING_ERROR);\n        }\n\n\t\tif (action == null && (request.getPath().startsWith(\"/api\") || request.getPath().startsWith(\"/admin\"))) {\n\t\t    action = ServerSetting.getErrorAction(ServerSetting.MAPPING_ERROR);\n        }\n\n\t\tif (null == action) {\n\t\t\t//查找匹配所有路径的Action\n\t\t\taction = ServerSetting.getAction(ServerSetting.MAPPING_ALL, request.getMethod());\n\t\t\tif(null == action){\n\t\t\t\t// 非Action方法，调用静态文件读取\n                if(request.getPath().startsWith(\"/fs\")) {\n                    action = Singleton.get(FileAction.class);\n                } else {\n                    action = ServerSetting.getErrorAction(ServerSetting.MAPPING_ERROR);\n                }\n\t\t\t}\n\t\t}\n        action.ctx = ctx;\n\n\t\tboolean isSync = action.doAction(request, response);\n\n\t\tif(isSync) {\n            //如果发送请求未被触发，则触发之，否则跳过。\n            if(!response.isSent()){\n                response.send();\n            }\n        }\n\t}\n\t//---------------------------------------------------------------------------------------- Private method start\n\n\n    private void handleOptions(ChannelHandlerContext ctx, Request request, Response response){\n\t    response.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n\t    response.setHeader(\"Access-Control-Allow-Headers\", \"*\");\n\t    response.send();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/handler/AdminActionHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.handler;\n\nimport com.xiaoleilu.loServer.ServerSetting;\nimport com.xiaoleilu.loServer.action.Action;\nimport com.xiaoleilu.loServer.action.FileAction;\nimport com.xiaoleilu.loServer.action.UnknownErrorAction;\nimport com.xiaoleilu.loServer.filter.Filter;\nimport io.moquette.spi.IMessagesStore;\nimport io.moquette.spi.ISessionsStore;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Action处理单元\n * \n * @author Looly\n */\npublic class AdminActionHandler extends ActionHandler {\n    private static final Logger Logger = LoggerFactory.getLogger(AdminActionHandler.class);\n\n    public AdminActionHandler(IMessagesStore messagesStore, ISessionsStore sessionsStore) {\n        super(messagesStore, sessionsStore);\n    }\n\n    @Override\n    boolean isValidePath(String path) {\n        if (path.startsWith(\"/admin\")) {\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/handler/HttpChunkContentCompressor.java",
    "content": "package com.xiaoleilu.loServer.handler;\n\nimport cn.hutool.log.StaticLog;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelPromise;\nimport io.netty.channel.FileRegion;\nimport io.netty.handler.codec.http.DefaultHttpResponse;\nimport io.netty.handler.codec.http.HttpContentCompressor;\n\n/**\n * 解决大文件传输与Gzip压缩冲突问题\n * @author Looly\n *\n */\npublic class HttpChunkContentCompressor extends HttpContentCompressor {\n\t@Override\n\tpublic void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {\n\t\tStaticLog.debug(\"Write object [{}]\", msg);\n\t\t\n\t\tif (msg instanceof FileRegion || msg instanceof DefaultHttpResponse) {\n\t\t\t//文件传输不经过Gzip压缩\n\t\t\tctx.write(msg, promise);\n\t\t}else{\n\t\t\tsuper.write(ctx, msg, promise);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/handler/HttpFileServerController.java",
    "content": "package com.xiaoleilu.loServer.handler;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class HttpFileServerController {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(HttpFileServerController.class);\n\tprivate Map<String, ChannelHandlerContext> contextMap = null; //\n\n\tprivate static class BrokenUploadInfoHandlerHolder {\n\t\tprivate static HttpFileServerController singleton = new HttpFileServerController();\n\t}\n\n\t/**\n\t * constructor\n\t */\n\tprivate HttpFileServerController() {\n\t\tcontextMap = new ConcurrentHashMap<String, ChannelHandlerContext>();\n\t}\n\n\t/**\n\t * getInstance\n\t */\n\tpublic static HttpFileServerController getInstance() {\n\t\treturn BrokenUploadInfoHandlerHolder.singleton;\n\t}\n\n\t/**\n\t * mapChannelHandlerContext\n\t * \n\t * @param requestId\n\t * @param ctx\n\t */\n\tpublic synchronized void mapChannelHandlerContext(String requestId, ChannelHandlerContext ctx) {\n\t\tif (contextMap.containsKey(requestId)) {\n\t\t\tlogger.warn(\"contextMap has already contained the key:\" + requestId);\n\t\t}\n\n\t\tcontextMap.put(requestId, ctx);\n\t}\n\n\t/**\n\t * getContext\n\t * \n\t * @param requestId\n\t * @return\n\t */\n\tpublic ChannelHandlerContext getChannelHandlerContext(String requestId) {\n\t\tif (!contextMap.containsKey(requestId)) {\n\t\t\tlogger.warn(\"contextMap not contains the key:\" + requestId);\n\t\t\treturn null;\n\t\t}\n\n\t\treturn contextMap.get(requestId);\n\t}\n\n\t/**\n\t * removeContext\n\t * \n\t * @param requestId\n\t */\n\tpublic void removeChannelHandlerContext(String requestId) {\n\t\tif (!contextMap.containsKey(requestId)) {\n\t\t\tlogger.warn(\"contextMap not contains the key:\" + requestId);\n\t\t\treturn;\n\t\t}\n\n\t\tcontextMap.remove(requestId);\n\t\t// logger.info(\"contextMap remove done.(\" + requestId + \")\");\n\t}\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/handler/HttpFileServerHandler.java",
    "content": "package com.xiaoleilu.loServer.handler;\n\nimport io.netty.util.internal.StringUtil;\nimport io.moquette.server.config.MediaServerConfig;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.codec.http.*;\nimport io.netty.handler.codec.http.multipart.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.io.RandomAccessFile;\nimport java.util.UUID;\n\nimport static com.xiaoleilu.loServer.handler.HttpResponseHelper.getFileExt;\nimport static io.netty.handler.codec.http.HttpHeaders.Names.*;\nimport static io.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_ALLOW_HEADERS;\nimport static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;\n\npublic class HttpFileServerHandler extends ChannelInboundHandlerAdapter {\n\n    private static final Logger logger = LoggerFactory.getLogger(HttpFileServerHandler.class);\n    private static final HttpDataFactory factory = new DefaultHttpDataFactory(false);\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) {\n        try {\n            if (msg instanceof FullHttpRequest) {\n                FullHttpRequest request = (FullHttpRequest) msg;\n                String requestId = UUID.randomUUID().toString().replace(\"-\", \"\");\n                logger.info(\"HttpFileServerHandler received a request: method=\" + request.getMethod() + \", uri=\" + request.getUri() + \", requestId=\" + requestId);\n\n                if (!request.getDecoderResult().isSuccess()) {\n                    logger.warn(\"http decode failed!\");\n                    HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST);\n                    return;\n                }\n\n                if (request.getMethod() == HttpMethod.GET) {\n                    download(ctx, request, requestId);\n                } else if (request.getMethod() == HttpMethod.POST) {\n                    multipartUpload(ctx, request, requestId);\n                } else if (request.getMethod() == HttpMethod.DELETE) {\n                    delete(ctx, request, requestId);\n                } else if (request.getMethod() == HttpMethod.OPTIONS) {\n                    doOptions(ctx, request);\n                } else {\n                    logger.warn(\"METHOD_NOT_ALLOWED!(methodName=\" + request.getMethod().name() + \")\");\n                    HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.METHOD_NOT_ALLOWED);\n                }\n            } else {\n                HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"Not a http request\");\n            }\n        } catch (Exception e) {\n            logger.error(\"HttpFileServerHandler.channelRead0() process error!\", e);\n            HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);\n        }\n    }\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {\n        try {\n            if (ctx.channel().isActive()) {\n                HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);\n                logger.warn(\"exceptionCaught:\" + cause.getMessage());\n            }\n        } catch (Exception e) {\n            logger.warn(\"exceptionCaught error!\" + e.getMessage());\n        }\n    }\n\n\n    /**\n     * multipart上传\n     */\n    private void multipartUpload(ChannelHandlerContext ctx, FullHttpRequest request, String requestId) {\n        HttpPostRequestDecoder decoder = null;\n        try {\n            decoder = new HttpPostRequestDecoder(factory, request);\n        } catch (HttpPostRequestDecoder.ErrorDataDecoderException e1) {\n            logger.error(\"Failed to decode file data!\", e1);\n            HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"Failed to decode file data!\");\n            return;\n        }\n\n\n        if (decoder != null) {\n            if (request instanceof HttpContent) {\n                HttpContent chunk = (HttpContent) request;\n                try {\n                    decoder.offer(chunk);\n                } catch (HttpPostRequestDecoder.ErrorDataDecoderException e1) {\n                    logger.warn(\"BAD_REQUEST, Failed to decode file data\");\n                    HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"Failed to decode file data\");\n                    return;\n                }\n\n                long fileTotalSize = 0;\n                if (request.headers().contains(\"X-File-Total-Size\")) {\n                    try {\n                        fileTotalSize = Integer.parseInt(request.headers().get(\"X-File-Total-Size\"));\n                    } catch (Exception e) {\n                        logger.warn(\"invalid X-File-Total-Size value!\");\n                    }\n                }\n                \n                readHttpDataChunkByChunk(ctx, decoder, requestId, HttpHeaders.isKeepAlive(request));\n\n                if (chunk instanceof LastHttpContent) {\n                    releaseRequest(request, decoder);\n                }\n            } else {\n                logger.warn(\"BAD_REQUEST, Not a http request\");\n                HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"Not a http request\");\n            }\n        }\n    }\n\n    /**\n     * readHttpDataChunkByChunk\n     */\n    private void readHttpDataChunkByChunk(ChannelHandlerContext ctx, HttpPostRequestDecoder decoder, String requestId, boolean isKeepAlive) {\n        try {\n            while (decoder.hasNext()) {\n                InterfaceHttpData data = decoder.next();\n                if (data != null) {\n                    try {\n                        writeFileUploadData(data, ctx, requestId, isKeepAlive);\n                    } finally {\n                        data.release();\n                    }\n                }\n            }\n        } catch (Exception e) {\n            logger.info(\"chunk end\");\n        }\n    }\n\n    /**\n     * writeFileUploadData\n     */\n    private void writeFileUploadData(InterfaceHttpData data, ChannelHandlerContext ctx, String requestId, boolean isKeepAlive) {\n        try {\n            if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {\n                FileUpload fileUpload = (FileUpload) data;\n\n                String remoteFileName = fileUpload.getFilename();\n                long remoteFileSize = fileUpload.length();\n                if (StringUtil.isNullOrEmpty(remoteFileName)) {\n                    logger.warn(\"remoteFileName is empty!\");\n                    HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"file name is empty\");\n                    return;\n                }\n\n                if (StringUtil.isNullOrEmpty(requestId)) {\n                    logger.warn(\"requestId is empty!\");\n                    HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"requestId is empty!\");\n                    return;\n                }\n\n                if (remoteFileSize > 10 * 1024 * 1024) {\n                    logger.warn(\"file over limite!(\" + remoteFileSize + \")\");\n                    HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"file over limite!\");\n                    return;\n                }\n\n\n\n                String remoteFileExt = \"\";\n                if (remoteFileName.lastIndexOf(\".\") == -1) {\n                    remoteFileExt = \"octetstream\";\n                    remoteFileName = remoteFileName + \".\" + remoteFileExt;\n\n                } else {\n                    remoteFileExt = getFileExt(remoteFileName);\n                }\n\n                if (StringUtil.isNullOrEmpty(remoteFileExt) || remoteFileExt.equals(\"ing\")) {\n                    logger.warn(\"Invalid file extention name\");\n                    HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"Invalid file extention name\");\n                    return;\n                }\n\n                int remoteFileTotalSize = (int) remoteFileSize;\n\n                HttpFileServerController.getInstance().mapChannelHandlerContext(requestId, ctx);\n\n                ByteBuf byteBuf = null;\n                int savedThunkSize = 0; // 分片接收保存的大小\n                int offset = 0; // 断点续传开始位置\n\n                File tmpFile = new File(\"./\" + MediaServerConfig.FILE_STROAGE_ROOT + \"/\" + requestId);\n\n                boolean isError = false;\n                while (true) {\n                    byte[] thunkData;\n                    try {\n                        byteBuf = fileUpload.getChunk(128 * 1024);\n                        int readableBytesSize = byteBuf.readableBytes();\n                        thunkData = new byte[readableBytesSize];\n                        byteBuf.readBytes(thunkData);\n\n                        put(tmpFile, offset, thunkData);\n\n                        savedThunkSize += readableBytesSize;\n                        offset += readableBytesSize;\n\n                        if (savedThunkSize >= remoteFileSize) {\n                            byteBuf.release();\n                            fileUpload.release();\n                            HttpResponseHelper.sendResponse(requestId, ctx, HttpResponseStatus.OK, HttpHeaders.Values.APPLICATION_JSON, \"{\\\"key\\\":\\\"\" + requestId + \"\\\"}\", true, false);\n                            break;\n                        }\n                    } catch (Exception e) {\n                        logger.error(\"save thunckData error!\", e);\n                        if (fileUpload != null)\n                            fileUpload.release();\n\n                        if (byteBuf != null)\n                            byteBuf.release();\n\n                        HttpResponseHelper.sendResponse(requestId, ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);\n                        isError = true;\n\n                        return;\n                    } finally {\n                        thunkData = null;\n                        if (isError) {\n                            tmpFile.delete();\n                        }\n                    }\n                }\n            }\n        } catch (Exception e) {\n            logger.error(\"writeHttpData error!\", e);\n            HttpResponseHelper.sendResponse(requestId, ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);\n        }\n    }\n\n    public static void put(File file, long pos, byte[] data) throws Exception {\n        RandomAccessFile raf = null;\n        try {\n            raf = new RandomAccessFile(file, \"rwd\");\n            raf.seek(pos);\n            raf.write(data);\n        } finally {\n            try {\n                if (raf != null)\n                    raf.close();\n            } catch (Exception e) {\n                logger.warn(\"release error!\", e);\n            }\n        }\n    }\n\n    /**\n     * 下载\n     */\n    private void download(ChannelHandlerContext ctx, FullHttpRequest request, String requestId) {\n//        try {\n//            final String httpUri = request.getUri();\n//            if (httpUri.toLowerCase().equals(\"/favicon.ico\")) {\n//                logger.warn(\"invalid httpUri(\" + httpUri + \", requestId=\" + requestId + \")\");\n//                HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"invalid httpUri\");\n//                return;\n//            }\n//\n//            String typedDownloadInfo = MetaDataIndexHandler.getTypedDownloadInfo(httpUri);\n//            if (StringUtil.isNullOrEmpty(typedDownloadInfo)) {\n//                logger.warn(\"invalid httpUri(\" + httpUri + \", requestId=\" + requestId + \")\");\n//                HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"invalid httpUri\");\n//                return;\n//            }\n//\n//            MetaDataIndex metadataIndex = MetaDataIndexHandler.parseTypedDownloadInfo(typedDownloadInfo);\n//            if (metadataIndex == null) {\n//                logger.warn(\"invalid typedDownloadInfo!(\" + typedDownloadInfo + \", requestId=\" + requestId + \")\");\n//                HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"invalid downloadFileName\");\n//                return;\n//            }\n//\n//            int fileSize = MetaDataHandler.getDataFieldLength(metadataIndex);\n//            int chunkSize = FileStorageConst.Stroage_Remote_Invoke_Thunk_Size;\n//            int chunkCount = fileSize % chunkSize == 0 ? (int) (fileSize / chunkSize) : (int) (fileSize / chunkSize + 1);\n//\n//            ClusterNode toNode = StorageClusterRouterManager.getInstance().getDownloadNode(metadataIndex.getClusterNode());\n//            if(toNode == null) {\n//                logger.warn(\"toNode is null!(\" + typedDownloadInfo + \", requestId=\" + requestId + \")\");\n//                HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.NOT_FOUND, \"File Not Existed\");\n//                return;\n//            }\n//\n//            ClusterNode fromNode = StorageClusterRouterManager.getInstance().getSelfNode();\n//            ActorSystem actorSystem = StorageClusterRouterManager.getInstance().getStorageActorSystem();\n//            ActorRef toActorRef = actorSystem.actorOf(toNode.getIp(), toNode.getRpcPort(), ActorType.DownloadActor.getName());\n//            ActorRef fromActorRef = actorSystem.actorOf(fromNode.getIp(),fromNode.getRpcPort(), ActorType.HttpFileServerActor.getName());\n//\n//            HttpFileServerController.getInstance().mapChannelHandlerContext(requestId, ctx);\n//\n//            DownloadMsg downloadMsg = new DownloadMsg();\n//            downloadMsg.setRequestId(requestId);\n//            downloadMsg.setIsKeepAlive(HttpHeaders.isKeepAlive(request));\n//            downloadMsg.setClusterNode(metadataIndex.getClusterNode());\n//            downloadMsg.setFileSize(fileSize);\n//            downloadMsg.setChunkIndex(0);\n//            downloadMsg.setChunkSize(chunkSize);\n//            downloadMsg.setChunkCount(chunkCount);\n//            downloadMsg.setTime(metadataIndex.getTime());\n//            downloadMsg.setBigFileIndex(metadataIndex.getBigFileIndex());\n//            downloadMsg.setOffset(metadataIndex.getOffset());\n//            downloadMsg.setMetaDataTotalLength(metadataIndex.getMetaDataTotalLength());\n//            downloadMsg.setFileType(metadataIndex.getFileType());\n//            downloadMsg.setBigFilePath(metadataIndex.getBigFilePath());\n//            downloadMsg.setStorageEngineVersion(metadataIndex.getStorageEngineVersion());\n//            toActorRef.tell(downloadMsg, fromActorRef);\n//        } catch (Exception e) {\n//            logger.error(\"download error!\", e);\n//            HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);\n//        } finally {\n//            releaseRequest(request, null);\n//        }\n    }\n\n    /**\n     * 删除\n     */\n    private void delete(ChannelHandlerContext ctx, FullHttpRequest request, String requestId) {\n//        try {\n//            final String httpUri = request.getUri();\n//            String typedDownloadInfo = MetaDataIndexHandler.getTypedDownloadInfo(httpUri);\n//            if (StringUtil.isNullOrEmpty(typedDownloadInfo)) {\n//                logger.warn(\"invalid httpUri(\" + httpUri + \")\");\n//                HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"invalid httpUri\");\n//                return;\n//            }\n//\n//            MetaDataIndex metadataIndex = MetaDataIndexHandler.parseTypedDownloadInfo(typedDownloadInfo);\n//            if (metadataIndex == null) {\n//                logger.warn(\"invalid typedDownloadInfo!(\" + typedDownloadInfo + \")\");\n//                HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.BAD_REQUEST, \"invalid downloadFileName\");\n//            }\n//\n//            ClusterNode toNode = StorageClusterRouterManager.getInstance().getClusterNode(metadataIndex.getClusterNode());\n//            ClusterNode fromNode = StorageClusterRouterManager.getInstance().getSelfNode();\n//            ActorSystem actorSystem = StorageClusterRouterManager.getInstance().getStorageActorSystem();\n//            ActorRef toActorRef = actorSystem.actorOf(toNode.getIp(), toNode.getRpcPort(), ActorType.DeleteActor.getName());\n//            ActorRef fromActorRef = actorSystem.actorOf(fromNode.getIp(),fromNode.getRpcPort(), ActorType.HttpFileServerActor.getName());\n//\n//            HttpFileServerController.getInstance().mapChannelHandlerContext(requestId, ctx);\n//\n//            DeleteMsg downloadMsg = new DeleteMsg();\n//            downloadMsg.setRequestId(requestId);\n//            downloadMsg.setIsKeepAlive(HttpHeaders.isKeepAlive(request));\n//            downloadMsg.setClusterNode(metadataIndex.getClusterNode());\n//            downloadMsg.setTime(metadataIndex.getTime());\n//            downloadMsg.setBigFileIndex(metadataIndex.getBigFileIndex());\n//            downloadMsg.setOffset(metadataIndex.getOffset());\n//            downloadMsg.setMetaDataTotalLength(metadataIndex.getMetaDataTotalLength());\n//            downloadMsg.setFileType(metadataIndex.getFileType());\n//            downloadMsg.setBigFilePath(metadataIndex.getBigFilePath());\n//            downloadMsg.setStorageEngineVersion(metadataIndex.getStorageEngineVersion());\n//            toActorRef.tell(downloadMsg, fromActorRef);\n//        } catch (Exception e) {\n//            logger.error(\"delete error!\", e);\n//            HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);\n//        } finally {\n//            releaseRequest(request, null);\n//        }\n    }\n\n    /**\n     * HTTP能力探测\n     */\n    private void doOptions(ChannelHandlerContext ctx, FullHttpRequest request) {\n        try {\n            boolean isKeepAlive = HttpHeaders.isKeepAlive(request);\n            FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.NO_CONTENT);\n            response.headers().set(CONTENT_TYPE, HttpHeaders.Values.APPLICATION_JSON);\n            response.headers().set(TRANSFER_ENCODING, \"chunked\");\n            if (isKeepAlive)\n                response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);\n            response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, \"*\");\n            response.headers().set(ACCESS_CONTROL_ALLOW_METHODS, \"GET, POST, DELETE, OPTIONS\");\n            response.headers().set(ACCESS_CONTROL_ALLOW_HEADERS, \"DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization\");\n\n            ChannelFuture future = ctx.channel().writeAndFlush(response);\n            if (!isKeepAlive) {\n                future.addListener(ChannelFutureListener.CLOSE);\n            }\n        } catch (Exception e) {\n            logger.error(\"doOptions error!\", e);\n            HttpResponseHelper.sendResponse(\"\", ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);\n        } finally {\n            releaseRequest(request, null);\n        }\n    }\n\n    /**\n     * releaseRequest\n     */\n    private void releaseRequest(FullHttpRequest request, HttpPostRequestDecoder decoder) {\n        try {\n            if (request != null)\n                request.release();\n\n            request = null;\n\n            if (decoder != null)\n                decoder.destroy();\n\n            decoder = null;\n        } catch (Exception e) {\n            logger.error(\"reset error!\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/handler/HttpResponseHelper.java",
    "content": "package com.xiaoleilu.loServer.handler;\n\nimport io.netty.util.internal.StringUtil;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.http.*;\nimport io.netty.util.CharsetUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static io.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_ALLOW_ORIGIN;\nimport static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_RANGE;\nimport static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;\nimport static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;\n\n\npublic class HttpResponseHelper {\n\nprivate static final Logger logger = LoggerFactory.getLogger(HttpResponseHelper.class);\n\n/**\n * sendResponse\n *\n * @param ctx\n * @param status\n */\npublic static void sendResponse(String requestId, ChannelHandlerContext ctx, HttpResponseStatus status) {\n    sendResponse(requestId, ctx, status, \"status: \" + status.toString() + \"\\r\\n\");\n    }\n\n/**\n * sendResponse\n *\n * @param ctx\n * @param status\n * @param msg\n */\npublic static void sendResponse(String requestId, ChannelHandlerContext ctx, HttpResponseStatus status, String msg) {\n    FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status, Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));\n    response.headers().set(CONTENT_TYPE, \"text/plain; charset=UTF-8\");\n    response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes());\n    response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, \"*\");\n    ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);\n\n    removeChannelHandlerContext(requestId, ctx);\n    }\n\n/**\n * sendResponse（成功应答需要注意isKeepAlive和isCloseChannel的值）\n *\n * @param requestId\n * @param ctx\n * @param status\n * @param contentType\n * @param respBodyString\n * @param isKeepAlive\n * @param isCloseChannel\n */\npublic static void sendResponse(String requestId, ChannelHandlerContext ctx, HttpResponseStatus status, String contentType, String respBodyString, boolean isKeepAlive, boolean isCloseChannel) {\n    FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(respBodyString, CharsetUtil.UTF_8));\n    if (!StringUtil.isNullOrEmpty(contentType)) {\n    response.headers().set(CONTENT_TYPE, contentType);\n    } else {\n    response.headers().set(CONTENT_TYPE, \"text/plain; charset=UTF-8\");\n    }\n\n    if (isKeepAlive) {\n    response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);\n    }\n\n    response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes());\n    response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, \"*\");\n\n    ChannelFuture future = ctx.channel().writeAndFlush(response);\n    if (!isKeepAlive) {\n    future.addListener(ChannelFutureListener.CLOSE);\n    }\n\n    removeChannelHandlerContext(requestId, ctx, isCloseChannel);\n    }\n\n/**\n * sendResponse\n *\n * @param ctx\n * @param statusCode\n * @param resultDesc\n */\npublic static void sendResponse(String requestId, ChannelHandlerContext ctx, int statusCode, String resultDesc) {\n    HttpResponseStatus httpResponseStatus = new HttpResponseStatus(statusCode, resultDesc);\n    FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, httpResponseStatus, Unpooled.copiedBuffer(resultDesc, CharsetUtil.UTF_8));\n    response.headers().set(CONTENT_TYPE, \"text/plain; charset=UTF-8\");\n    response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes());\n    response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, \"*\");\n    ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);\n\n    removeChannelHandlerContext(requestId, ctx);\n    }\n\n/**\n * 断点上传204应答\n *\n * @param ctx\n * @param contentRange\n */\npublic static void sendBrokenUpload204Resonse(String requestId, ChannelHandlerContext ctx, String contentRange, boolean isKeepAlive, boolean isCloseChannel) {\n    FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.NO_CONTENT, Unpooled.copiedBuffer(\"\", CharsetUtil.UTF_8));\n    response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, \"*\");\n    response.headers().set(CONTENT_RANGE, contentRange);\n\n    ChannelFuture future = ctx.channel().writeAndFlush(response);\n    if (!isKeepAlive) {\n    future.addListener(ChannelFutureListener.CLOSE);\n    }\n\n    removeChannelHandlerContext(requestId, ctx, isCloseChannel);\n    }\n\n\npublic static String getMultipartUploadResponseBody(String remoteFileName, String fileUrl) throws Exception {\n\n    return \"{\\\"rc_url\\\":{\\\"path\\\":\\\"\" + fileUrl + \"\\\",\\\"type\\\":0}}\";\n}\n\n/**\n * getContentType\n *\n * @param fileName\n * @return\n */\n\npublic static String getFileExt(String fileName) {\n    int index = fileName.lastIndexOf(\".\");\n    if (index == -1) {\n        return \"\";\n    }\n\n    return fileName.substring(index + 1).toLowerCase();\n}\n\npublic static String getContentType(String fileName) {\n    String fileExtName = getFileExt(fileName);\n    if (fileExtName.equals(\"png\")) { // MimetypesFileTypeMap目前缺少png类型\n    return \"image/png\";\n    } else {\n    return \"application/octet-stream\";\n    }\n    }\n\n/**\n * removeChannelHandlerContext\n *\n * @param requestId\n * @param ctx\n */\nprivate static void removeChannelHandlerContext(String requestId, ChannelHandlerContext ctx) {\n    removeChannelHandlerContext(requestId, ctx, true);\n    }\n\nprivate static void removeChannelHandlerContext(String requestId, ChannelHandlerContext ctx, boolean isCloseChannel) {\n    try {\n    if (!StringUtil.isNullOrEmpty(requestId)) {\n//    HttpFileServerController.getInstance().removeChannelHandlerContext(requestId);\n    }\n\n    if (isCloseChannel)\n    ctx.channel().close();\n    } catch (Exception e) {\n    logger.error(\"close error!\", e);\n    }\n    }\n    }\n\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/handler/IMActionHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.handler;\n\nimport com.xiaoleilu.loServer.ServerSetting;\nimport com.xiaoleilu.loServer.action.Action;\nimport com.xiaoleilu.loServer.action.FileAction;\nimport com.xiaoleilu.loServer.action.UnknownErrorAction;\nimport com.xiaoleilu.loServer.filter.Filter;\nimport io.moquette.spi.IMessagesStore;\nimport io.moquette.spi.ISessionsStore;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.SimpleChannelInboundHandler;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.util.internal.StringUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Action处理单元\n * \n * @author Looly\n */\npublic class IMActionHandler extends ActionHandler {\n    private static final Logger Logger = LoggerFactory.getLogger(IMActionHandler.class);\n\n    public IMActionHandler(IMessagesStore messagesStore, ISessionsStore sessionsStore) {\n        super(messagesStore, sessionsStore);\n    }\n\n    @Override\n    boolean isValidePath(String path) {\n        if (!StringUtil.isNullOrEmpty(path) && !path.startsWith(\"/admin\")) {\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/handler/Request.java",
    "content": "package com.xiaoleilu.loServer.handler;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.nio.charset.Charset;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Set;\n\nimport cn.hutool.core.convert.Convert;\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.net.NetUtil;\nimport cn.hutool.core.util.CharsetUtil;\nimport cn.hutool.core.util.StrUtil;\nimport cn.hutool.core.util.URLUtil;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.HttpHeaderNames;\nimport io.netty.handler.codec.http.HttpHeaderValues;\nimport io.netty.handler.codec.http.HttpHeaders;\nimport io.netty.handler.codec.http.HttpMethod;\nimport io.netty.handler.codec.http.HttpRequest;\nimport io.netty.handler.codec.http.HttpVersion;\nimport io.netty.handler.codec.http.QueryStringDecoder;\nimport io.netty.handler.codec.http.cookie.Cookie;\nimport io.netty.handler.codec.http.cookie.ServerCookieDecoder;\nimport io.netty.handler.codec.http.multipart.Attribute;\nimport io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;\nimport io.netty.handler.codec.http.multipart.FileUpload;\nimport io.netty.handler.codec.http.multipart.HttpDataFactory;\nimport io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;\nimport io.netty.handler.codec.http.multipart.InterfaceHttpData;\nimport io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;\nimport org.slf4j.LoggerFactory;\n\n/**\n * Http请求对象\n * \n * @author Looly\n *\n */\npublic class Request {\n    private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(Request.class);\n\n\tpublic static final String METHOD_DELETE = HttpMethod.DELETE.name();\n\tpublic static final String METHOD_HEAD = HttpMethod.HEAD.name();\n\tpublic static final String METHOD_GET = HttpMethod.GET.name();\n\tpublic static final String METHOD_OPTIONS = HttpMethod.OPTIONS.name();\n\tpublic static final String METHOD_POST = HttpMethod.POST.name();\n\tpublic static final String METHOD_PUT = HttpMethod.PUT.name();\n\tpublic static final String METHOD_TRACE = HttpMethod.TRACE.name();\n\n\tprivate static final HttpDataFactory HTTP_DATA_FACTORY = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);\n\n\tprivate FullHttpRequest nettyRequest;\n\n\tprivate String path;\n\tprivate String ip;\n\tprivate Map<String, String> headers = new HashMap<String, String>();\n\tprivate Map<String, Object> params = new HashMap<String, Object>();\n\tprivate Map<String, Cookie> cookies = new HashMap<String, Cookie>();\n\n\t/**\n\t * 构造\n\t * \n\t * @param ctx ChannelHandlerContext\n\t * @param nettyRequest HttpRequest\n\t */\n\tprivate Request(ChannelHandlerContext ctx, FullHttpRequest nettyRequest) {\n\t\tthis.nettyRequest = nettyRequest;\n\t\tfinal String uri = nettyRequest.uri();\n\t\tthis.path = URLUtil.getPath(getUri());\n\n\t\tthis.putHeadersAndCookies(nettyRequest.headers());\n\n\t\t// request URI parameters\n\t\tthis.putParams(new QueryStringDecoder(uri));\n\n\t\t// IP\n\t\tthis.putIp(ctx);\n\t}\n\n\t/**\n\t * @return Netty的HttpRequest\n\t */\n\tpublic HttpRequest getNettyRequest() {\n\t\treturn this.nettyRequest;\n\t}\n\n\t/**\n\t * 获得版本信息\n\t * \n\t * @return 版本\n\t */\n\tpublic String getProtocolVersion() {\n\t\treturn nettyRequest.protocolVersion().text();\n\t}\n\n\t/**\n\t * 获得URI（带参数的路径）\n\t * \n\t * @return URI\n\t */\n\tpublic String getUri() {\n\t\treturn nettyRequest.uri();\n\t}\n\n\t/**\n\t * @return 获得path（不带参数的路径）\n\t */\n\tpublic String getPath() {\n\t\treturn path;\n\t}\n\n\t/**\n\t * 获得Http方法\n\t * \n\t * @return Http method\n\t */\n\tpublic String getMethod() {\n\t\treturn nettyRequest.method().name();\n\t}\n\n\t/**\n\t * 获得IP地址\n\t * \n\t * @return IP地址\n\t */\n\tpublic String getIp() {\n\t\treturn ip;\n\t}\n\n\t/**\n\t * 获得所有头信息\n\t * \n\t * @return 头信息Map\n\t */\n\tpublic Map<String, String> getHeaders() {\n\t\treturn headers;\n\t}\n\n\t/**\n\t * 使用ISO8859_1字符集获得Header内容<br>\n\t * 由于Header中很少有中文，故一般情况下无需转码\n\t * \n\t * @param headerKey 头信息的KEY\n\t * @return 值\n\t */\n\tpublic String getHeader(String headerKey) {\n\t\treturn headers.get(headerKey);\n\t}\n\n\t/**\n\t * @return 是否为普通表单（application/x-www-form-urlencoded）\n\t */\n\tpublic boolean isXWwwFormUrlencoded() {\n\t\treturn \"application/x-www-form-urlencoded\".equals(getHeader(\"Content-Type\"));\n\t}\n\n\t/**\n\t * 获得指定的Cookie\n\t * \n\t * @param name cookie名\n\t * @return Cookie对象\n\t */\n\tpublic Cookie getCookie(String name) {\n\t\treturn cookies.get(name);\n\t}\n\n\t/**\n\t * @return 获得所有Cookie信息\n\t */\n\tpublic Map<String, Cookie> getCookies() {\n\t\treturn this.cookies;\n\t}\n\n\t/**\n\t * @return 客户浏览器是否为IE\n\t */\n\tpublic boolean isIE() {\n\t\tString userAgent = getHeader(\"User-Agent\");\n\t\tif (StrUtil.isNotBlank(userAgent)) {\n\t\t\tuserAgent = userAgent.toUpperCase();\n\t\t\tif (userAgent.contains(\"MSIE\") || userAgent.contains(\"TRIDENT\")) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * @param name 参数名\n\t * @return 获得请求参数\n\t */\n\tpublic String getParam(String name) {\n\t\tfinal Object value = params.get(name);\n\t\tif(null == value){\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\tif(value instanceof String){\n\t\t\treturn (String)value;\n\t\t}\n\t\treturn value.toString();\n\t}\n\t\n\t/**\n\t * @param name 参数名\n\t * @return 获得请求参数\n\t */\n\tpublic Object getObjParam(String name) {\n\t\treturn params.get(name);\n\t}\n\n\t/**\n\t * 获得GET请求参数<br>\n\t * 会根据浏览器类型自动识别GET请求的编码方式从而解码<br>\n\t * charsetOfServlet为null则默认的ISO_8859_1\n\t * \n\t * @param name 参数名\n\t * @param charset 字符集\n\t * @return 获得请求参数\n\t */\n\tpublic String getParam(String name, Charset charset) {\n\t\tif (null == charset) {\n\t\t\tcharset = Charset.forName(CharsetUtil.ISO_8859_1);\n\t\t}\n\n\t\tString destCharset = CharsetUtil.UTF_8;\n\t\tif (isIE()) {\n\t\t\t// IE浏览器GET请求使用GBK编码\n\t\t\tdestCharset = CharsetUtil.GBK;\n\t\t}\n\n\t\tString value = getParam(name);\n\t\tif (METHOD_GET.equalsIgnoreCase(getMethod())) {\n\t\t\tvalue = CharsetUtil.convert(value, charset.toString(), destCharset);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * @param name 参数名\n\t * @param defaultValue 当客户端未传参的默认值\n\t * @return 获得请求参数\n\t */\n\tpublic String getParam(String name, String defaultValue) {\n\t\tString param = getParam(name);\n\t\treturn StrUtil.isBlank(param) ? defaultValue : param;\n\t}\n\n\t/**\n\t * @param name 参数名\n\t * @param defaultValue 当客户端未传参的默认值\n\t * @return 获得Integer类型请求参数\n\t */\n\tpublic Integer getIntParam(String name, Integer defaultValue) {\n\t\treturn Convert.toInt(getParam(name), defaultValue);\n\t}\n\n\t/**\n\t * @param name 参数名\n\t * @param defaultValue 当客户端未传参的默认值\n\t * @return 获得long类型请求参数\n\t */\n\tpublic Long getLongParam(String name, Long defaultValue) {\n\t\treturn Convert.toLong(getParam(name), defaultValue);\n\t}\n\n\t/**\n\t * @param name 参数名\n\t * @param defaultValue 当客户端未传参的默认值\n\t * @return 获得Double类型请求参数\n\t */\n\tpublic Double getDoubleParam(String name, Double defaultValue) {\n\t\treturn Convert.toDouble(getParam(name), defaultValue);\n\t}\n\n\t/**\n\t * @param name 参数名\n\t * @param defaultValue 当客户端未传参的默认值\n\t * @return 获得Float类型请求参数\n\t */\n\tpublic Float getFloatParam(String name, Float defaultValue) {\n\t\treturn Convert.toFloat(getParam(name), defaultValue);\n\t}\n\n\t/**\n\t * @param name 参数名\n\t * @param defaultValue 当客户端未传参的默认值\n\t * @return 获得Boolean类型请求参数\n\t */\n\tpublic Boolean getBoolParam(String name, Boolean defaultValue) {\n\t\treturn Convert.toBool(getParam(name), defaultValue);\n\t}\n\n\t/**\n\t * 格式：<br>\n\t * 1、yyyy-MM-dd HH:mm:ss <br>\n\t * 2、yyyy-MM-dd <br>\n\t * 3、HH:mm:ss <br>\n\t * \n\t * @param name 参数名\n\t * @param defaultValue 当客户端未传参的默认值\n\t * @return 获得Date类型请求参数，默认格式：\n\t */\n\tpublic Date getDateParam(String name, Date defaultValue) {\n\t\tString param = getParam(name);\n\t\treturn StrUtil.isBlank(param) ? defaultValue : DateUtil.parse(param);\n\t}\n\n\t/**\n\t * @param name 参数名\n\t * @param format 格式\n\t * @param defaultValue 当客户端未传参的默认值\n\t * @return 获得Date类型请求参数\n\t */\n\tpublic Date getDateParam(String name, String format, Date defaultValue) {\n\t\tString param = getParam(name);\n\t\treturn StrUtil.isBlank(param) ? defaultValue : DateUtil.parse(param, format);\n\t}\n\n\t/**\n\t * 获得请求参数<br>\n\t * 列表类型值，常用于表单中的多选框\n\t * \n\t * @param name 参数名\n\t * @return 数组\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic List<String> getArrayParam(String name) {\n\t\tObject value = params.get(name);\n\t\tif(null == value){\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\tif(value instanceof List){\n\t\t\treturn (List<String>) value;\n\t\t}else if(value instanceof String){\n\t\t\treturn StrUtil.split((String)value, ',');\n\t\t}else{\n\t\t\tthrow new RuntimeException(\"Value is not a List type!\");\n\t\t}\n\t}\n\n\t/**\n\t * 获得所有请求参数\n\t * \n\t * @return Map\n\t */\n\tpublic Map<String, Object> getParams() {\n\t\treturn params;\n\t}\n\n\t/**\n\t * @return 是否为长连接\n\t */\n\tpublic boolean isKeepAlive() {\n\t\tfinal String connectionHeader = getHeader(HttpHeaderNames.CONNECTION.toString());\n\t\t// 无论任何版本Connection为close时都关闭连接\n\t\tif (HttpHeaderValues.CLOSE.toString().equalsIgnoreCase(connectionHeader)) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// HTTP/1.0只有Connection为Keep-Alive时才会保持连接\n\t\tif (HttpVersion.HTTP_1_0.text().equals(getProtocolVersion())) {\n\t\t\tif (false == HttpHeaderValues.KEEP_ALIVE.toString().equalsIgnoreCase(connectionHeader)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\t// HTTP/1.1默认打开Keep-Alive\n\t\treturn true;\n\t}\n\n\t// --------------------------------------------------------- Protected method start\n\t/**\n\t * 填充参数（GET请求的参数）\n\t * \n\t * @param decoder QueryStringDecoder\n\t */\n\tprotected void putParams(QueryStringDecoder decoder) {\n\t\tif (null != decoder) {\n\t\t\tList<String> valueList;\n\t\t\tfor (Entry<String, List<String>> entry : decoder.parameters().entrySet()) {\n\t\t\t\tvalueList = entry.getValue();\n\t\t\t\tif(null != valueList){\n\t\t\t\t\tthis.putParam(entry.getKey(), 1 == valueList.size() ? valueList.get(0) : valueList);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 填充参数（POST请求的参数）\n\t * \n\t * @param decoder QueryStringDecoder\n\t */\n\tprotected void putParams(HttpPostRequestDecoder decoder) {\n\t\tif (null == decoder) {\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tfor (InterfaceHttpData data : decoder.getBodyHttpDatas()) {\n\t\t\tputParam(data);\n\t\t}\n\t}\n\t\n\t/**\n\t * 填充参数\n\t * \n\t * @param data InterfaceHttpData\n\t */\n\tprotected void putParam(InterfaceHttpData data) {\n\t\tfinal HttpDataType dataType = data.getHttpDataType();\n\t\tif (dataType == HttpDataType.Attribute) {\n\t\t\t//普通参数\n\t\t\tAttribute attribute = (Attribute) data;\n\t\t\ttry {\n\t\t\t\tthis.putParam(attribute.getName(), attribute.getValue());\n\t\t\t} catch (IOException e) {\n                Logger.error(e.toString());\n\t\t\t}\n\t\t}else if(dataType == HttpDataType.FileUpload){\n\t\t\t//文件\n\t\t\tFileUpload fileUpload = (FileUpload) data;\n\t\t\tif(fileUpload.isCompleted()){\n\t\t\t\ttry {\n\t\t\t\t\tthis.putParam(data.getName(), fileUpload.getFile());\n\t\t\t\t} catch (IOException e) {\n                    Logger.error(e.toString(), \"Get file param [{}] error!\", data.getName());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 填充参数\n\t * \n\t * @param key 参数名\n\t * @param value 参数值\n\t */\n\tprotected void putParam(String key, Object value) {\n\t\tthis.params.put(key, value);\n\t}\n\n\t/**\n\t * 填充头部信息和Cookie信息\n\t * \n\t * @param headers HttpHeaders\n\t */\n\tprotected void putHeadersAndCookies(HttpHeaders headers) {\n\t\tfor (Entry<String, String> entry : headers) {\n\t\t\tthis.headers.put(entry.getKey(), entry.getValue());\n\t\t}\n\n\t\t// Cookie\n\t\tfinal String cookieString = this.headers.get(HttpHeaderNames.COOKIE);\n\t\tif (StrUtil.isNotBlank(cookieString)) {\n\t\t\tfinal Set<Cookie> cookies = ServerCookieDecoder.LAX.decode(cookieString);\n\t\t\tfor (Cookie cookie : cookies) {\n\t\t\t\tthis.cookies.put(cookie.name(), cookie);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 设置客户端IP\n\t * \n\t * @param ctx ChannelHandlerContext\n\t */\n\tprotected void putIp(ChannelHandlerContext ctx) {\n\t\tString ip = getHeader(\"X-Forwarded-For\");\n\t\tif (StrUtil.isNotBlank(ip)) {\n\t\t\tip = NetUtil.getMultistageReverseProxyIp(ip);\n\t\t} else {\n\t\t\tfinal InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();\n\t\t\tip = insocket.getAddress().getHostAddress();\n\t\t}\n\t\tthis.ip = ip;\n\t}\n\t// --------------------------------------------------------- Protected method end\n\n\t@Override\n\tpublic String toString() {\n\t\tfinal StringBuilder sb = new StringBuilder();\n\t\tsb.append(\"\\r\\nprotocolVersion: \").append(getProtocolVersion()).append(\"\\r\\n\");\n\t\tsb.append(\"uri: \").append(getUri()).append(\"\\r\\n\");\n\t\tsb.append(\"path: \").append(path).append(\"\\r\\n\");\n\t\tsb.append(\"method: \").append(getMethod()).append(\"\\r\\n\");\n\t\tsb.append(\"ip: \").append(ip).append(\"\\r\\n\");\n\t\tsb.append(\"headers:\\r\\n \");\n\t\tfor (Entry<String, String> entry : headers.entrySet()) {\n\t\t\tsb.append(\"    \").append(entry.getKey()).append(\": \").append(entry.getValue()).append(\"\\r\\n\");\n\t\t}\n\t\tsb.append(\"params: \\r\\n\");\n\t\tfor (Entry<String, Object> entry : params.entrySet()) {\n\t\t\tsb.append(\"    \").append(entry.getKey()).append(\": \").append(entry.getValue()).append(\"\\r\\n\");\n\t\t}\n\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 构建Request对象\n\t * \n\t * @param ctx ChannelHandlerContext\n\t * @param nettyRequest Netty的HttpRequest\n\t * @return Request\n\t */\n\tprotected final static Request build(ChannelHandlerContext ctx, FullHttpRequest nettyRequest) {\n\t\treturn new Request(ctx, nettyRequest);\n\t}\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/handler/Response.java",
    "content": "package com.xiaoleilu.loServer.handler;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.charset.Charset;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.GregorianCalendar;\nimport java.util.HashSet;\nimport java.util.Locale;\nimport java.util.Map.Entry;\nimport java.util.Set;\nimport java.util.TimeZone;\n\nimport cn.hutool.core.date.DateUtil;\nimport cn.hutool.core.util.CharsetUtil;\nimport cn.hutool.core.util.StrUtil;\nimport com.xiaoleilu.loServer.ServerSetting;\nimport com.xiaoleilu.loServer.listener.FileProgressiveFutureListener;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.ChannelFutureListener;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.DefaultFileRegion;\nimport io.netty.handler.codec.http.DefaultFullHttpResponse;\nimport io.netty.handler.codec.http.DefaultHttpHeaders;\nimport io.netty.handler.codec.http.DefaultHttpResponse;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport io.netty.handler.codec.http.HttpHeaderNames;\nimport io.netty.handler.codec.http.HttpHeaderValues;\nimport io.netty.handler.codec.http.HttpHeaders;\nimport io.netty.handler.codec.http.HttpResponseStatus;\nimport io.netty.handler.codec.http.HttpVersion;\nimport io.netty.handler.codec.http.LastHttpContent;\nimport io.netty.handler.codec.http.cookie.Cookie;\nimport io.netty.handler.codec.http.cookie.DefaultCookie;\nimport io.netty.handler.codec.http.cookie.ServerCookieEncoder;\nimport org.apache.tika.Tika;\nimport org.slf4j.LoggerFactory;\n\nimport static cn.hutool.core.date.DatePattern.HTTP_DATETIME_PATTERN;\n\n/**\n * 响应对象\n * \n * @author Looly\n *\n */\npublic class Response {\n    private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(Response.class);\n\n\t/** 返回内容类型：普通文本 */\n\tpublic final static String CONTENT_TYPE_TEXT = \"text/plain\";\n\t/** 返回内容类型：HTML */\n\tpublic final static String CONTENT_TYPE_HTML = \"text/html\";\n\t/** 返回内容类型：XML */\n\tpublic final static String CONTENT_TYPE_XML = \"text/xml\";\n\t/** 返回内容类型：JAVASCRIPT */\n\tpublic final static String CONTENT_TYPE_JAVASCRIPT = \"application/javascript\";\n\t/** 返回内容类型：JSON */\n\tpublic final static String CONTENT_TYPE_JSON = \"application/json\";\n\tpublic final static String CONTENT_TYPE_JSON_IE = \"text/json\";\n\n\tprivate ChannelHandlerContext ctx;\n\tprivate Request request;\n\n\tprivate HttpVersion httpVersion = HttpVersion.HTTP_1_1;\n\tprivate HttpResponseStatus status = HttpResponseStatus.OK;\n\tprivate String contentType = CONTENT_TYPE_HTML;\n\tprivate String charset = ServerSetting.getCharset();\n\tprivate HttpHeaders headers = new DefaultHttpHeaders();\n\tprivate Set<Cookie> cookies = new HashSet<Cookie>();\n\tprivate Object content = Unpooled.EMPTY_BUFFER;\n\t//发送完成标记\n\tprivate boolean isSent;\n\n\tpublic Response(ChannelHandlerContext ctx, Request request) {\n\t\tthis.ctx = ctx;\n\t\tthis.request = request;\n\t}\n\n\t/**\n\t * 设置响应的Http版本号\n\t * \n\t * @param httpVersion http版本号对象\n\t * @return 自己\n\t */\n\tpublic Response setHttpVersion(HttpVersion httpVersion) {\n\t\tthis.httpVersion = httpVersion;\n\t\treturn this;\n\t}\n\n\t/**\n\t * 响应状态码<br>\n\t * 使用io.netty.handler.codec.http.HttpResponseStatus对象\n\t * \n\t * @param status 状态码\n\t * @return 自己\n\t */\n\tpublic Response setStatus(HttpResponseStatus status) {\n\t\tthis.status = status;\n\t\treturn this;\n\t}\n\n\t/**\n\t * 响应状态码\n\t * \n\t * @param status 状态码\n\t * @return 自己\n\t */\n\tpublic Response setStatus(int status) {\n\t\treturn setStatus(HttpResponseStatus.valueOf(status));\n\t}\n\n\t/**\n\t * 设置Content-Type\n\t * \n\t * @param contentType Content-Type\n\t * @return 自己\n\t */\n\tpublic Response setContentType(String contentType) {\n\t\tthis.contentType = contentType;\n\t\treturn this;\n\t}\n\n\t/**\n\t * 设置返回内容的字符集编码\n\t * \n\t * @param charset 编码\n\t * @return 自己\n\t */\n\tpublic Response setCharset(String charset) {\n\t\tthis.charset = charset;\n\t\treturn this;\n\t}\n\n\t/**\n\t * 增加响应的Header<br>\n\t * 重复的Header将被叠加\n\t * \n\t * @param name 名\n\t * @param value 值，可以是String，Date， int\n\t * @return 自己\n\t */\n\tpublic Response addHeader(String name, Object value) {\n\t\theaders.add(name, value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * 设置响应的Header<br>\n\t * 重复的Header将被替换\n\t * \n\t * @param name 名\n\t * @param value 值，可以是String，Date， int\n\t * @return 自己\n\t */\n\tpublic Response setHeader(String name, Object value) {\n\t\theaders.set(name, value);\n\t\treturn this;\n\t}\n\n\t/**\n\t * 设置响应体长度\n\t * \n\t * @param contentLength 响应体长度\n\t * @return 自己\n\t */\n\tpublic Response setContentLength(long contentLength) {\n\t\tsetHeader(HttpHeaderNames.CONTENT_LENGTH.toString(), contentLength);\n\t\treturn this;\n\t}\n\n\t/**\n\t * 设置是否长连接\n\t * \n\t * @return 自己\n\t */\n\tpublic Response setKeepAlive() {\n\t\tsetHeader(HttpHeaderNames.CONNECTION.toString(), HttpHeaderValues.KEEP_ALIVE.toString());\n\t\treturn this;\n\t}\n\n\t// --------------------------------------------------------- Cookie start\n\t/**\n\t * 设定返回给客户端的Cookie\n\t * \n\t * @param cookie\n\t * @return 自己\n\t */\n\tpublic Response addCookie(Cookie cookie) {\n\t\tcookies.add(cookie);\n\t\treturn this;\n\t}\n\n\t/**\n\t * 设定返回给客户端的Cookie\n\t * \n\t * @param name Cookie名\n\t * @param value Cookie值\n\t * @return 自己\n\t */\n\tpublic Response addCookie(String name, String value) {\n\t\treturn addCookie(new DefaultCookie(name, value));\n\t}\n\n\t/**\n\t * 设定返回给客户端的Cookie\n\t * \n\t * @param name cookie名\n\t * @param value cookie值\n\t * @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. n>0 : Cookie存在的秒数.\n\t * @param path Cookie的有效路径\n\t * @param domain the Cookie可见的域，依据 RFC 2109 标准\n\t * @return 自己\n\t */\n\tpublic Response addCookie(String name, String value, int maxAgeInSeconds, String path, String domain) {\n\t\tCookie cookie = new DefaultCookie(name, value);\n\t\tif (domain != null) {\n\t\t\tcookie.setDomain(domain);\n\t\t}\n\t\tcookie.setMaxAge(maxAgeInSeconds);\n\t\tcookie.setPath(path);\n\t\treturn addCookie(cookie);\n\t}\n\n\t/**\n\t * 设定返回给客户端的Cookie<br>\n\t * Path: \"/\"<br>\n\t * No Domain\n\t * \n\t * @param name cookie名\n\t * @param value cookie值\n\t * @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. n>0 : Cookie存在的秒数.\n\t * @return 自己\n\t */\n\tpublic Response addCookie(String name, String value, int maxAgeInSeconds) {\n\t\treturn addCookie(name, value, maxAgeInSeconds, \"/\", null);\n\t}\n\t// --------------------------------------------------------- Cookie end\n\n\t/**\n\t * 设置响应HTML文本内容\n\t * \n\t * @param contentText 响应的文本\n\t * @return 自己\n\t */\n\tpublic Response setContent(String contentText) {\n\t\tthis.content = Unpooled.copiedBuffer(contentText, Charset.forName(charset));\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 设置响应文本内容\n\t * \n\t * @param contentText 响应的文本\n\t * @return 自己\n\t */\n\tpublic Response setTextContent(String contentText) {\n\t\tsetContentType(CONTENT_TYPE_TEXT);\n\t\treturn setContent(contentText);\n\t}\n\t\n\t/**\n\t * 设置响应JSON文本内容\n\t * \n\t * @param contentText 响应的JSON文本\n\t * @return 自己\n\t */\n\tpublic Response setJsonContent(String contentText) {\n\t\tsetContentType(request.isIE() ? CONTENT_TYPE_JSON : CONTENT_TYPE_JSON);\n\t\treturn setContent(contentText);\n\t}\n\t\n\t/**\n\t * 设置响应XML文本内容\n\t * \n\t * @param contentText 响应的XML文本\n\t * @return 自己\n\t */\n\tpublic Response setXmlContent(String contentText) {\n\t\tsetContentType(CONTENT_TYPE_XML);\n\t\treturn setContent(contentText);\n\t}\n\n\t/**\n\t * 设置响应文本内容\n\t * \n\t * @param contentBytes 响应的字节\n\t * @return 自己\n\t */\n\tpublic Response setContent(byte[] contentBytes) {\n\t\treturn setContent(Unpooled.copiedBuffer(contentBytes));\n\t}\n\n\t/**\n\t * 设置响应文本内容\n\t * \n\t * @param byteBuf 响应的字节\n\t * @return 自己\n\t */\n\tpublic Response setContent(ByteBuf byteBuf) {\n\t\tthis.content = byteBuf;\n\t\treturn this;\n\t}\n\t\n\t/**\n\t * 设置响应到客户端的文件\n\t * \n\t * @param file 文件\n\t * @return 自己\n\t */\n\tpublic Response setContent(File file) {\n\t\tthis.content = file;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the Date and Cache headers for the HTTP Response\n\t *\n\t * @param response HTTP response\n\t * @param fileToCache file to extract content type\n\t */\n\t/**\n\t * 设置日期和过期时间\n\t * \n\t * @param lastModify 上一次修改时间\n\t * @param httpCacheSeconds 缓存时间，单位秒\n\t */\n\tpublic void setDateAndCache(long lastModify, int httpCacheSeconds) {\n\t\tSimpleDateFormat formatter = new SimpleDateFormat(HTTP_DATETIME_PATTERN, Locale.US);\n\t\tformatter.setTimeZone(TimeZone.getTimeZone(\"GMT\"));\n\n\t\t// Date header\n\t\tCalendar time = new GregorianCalendar();\n\t\tsetHeader(HttpHeaderNames.DATE.toString(), formatter.format(time.getTime()));\n\n\t\t// Add cache headers\n\t\ttime.add(Calendar.SECOND, httpCacheSeconds);\n\n\t\tsetHeader(HttpHeaderNames.EXPIRES.toString(), formatter.format(time.getTime()));\n\t\tsetHeader(HttpHeaderNames.CACHE_CONTROL.toString(), \"private, max-age=\" + httpCacheSeconds);\n\t\tsetHeader(HttpHeaderNames.LAST_MODIFIED.toString(), formatter.format(DateUtil.date(lastModify)));\n\t}\n\n\t// -------------------------------------------------------------------------------------- build HttpResponse start\n\t/**\n\t * 转换为Netty所用Response<br>\n\t * 不包括content，一般用于返回文件类型的响应\n\t * \n\t * @return DefaultHttpResponse\n\t */\n\tprivate DefaultHttpResponse toDefaultHttpResponse() {\n\t\tfinal DefaultHttpResponse defaultHttpResponse = new DefaultHttpResponse(httpVersion, status);\n\n\t\t// headers\n\t\tHttpHeaders httpHeaders = defaultHttpResponse.headers().add(headers);\n        httpHeaders.set(HttpHeaderNames.CONTENT_TYPE.toString(), contentType);\n\t\t// Cookies\n\t\tfor (Cookie cookie : cookies) {\n\t\t\thttpHeaders.add(HttpHeaderNames.SET_COOKIE.toString(), ServerCookieEncoder.LAX.encode(cookie));\n\t\t}\n\n\t\treturn defaultHttpResponse;\n\t}\n\n\t/**\n\t * 转换为Netty所用Response<br>\n\t * 用于返回一般类型响应（文本）\n\t * \n\t * @return FullHttpResponse\n\t */\n\tprivate FullHttpResponse toFullHttpResponse() {\n\t\tfinal ByteBuf byteBuf = (ByteBuf)content;\n\t\tfinal FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(httpVersion, status, byteBuf);\n\n\t\t// headers\n\t\tfinal HttpHeaders httpHeaders = fullHttpResponse.headers().add(headers);\n\t\tif (\"application/octet-stream\".equals(contentType)) {\n            httpHeaders.set(HttpHeaderNames.CONTENT_TYPE.toString(), contentType);\n        } else {\n            httpHeaders.set(HttpHeaderNames.CONTENT_TYPE.toString(), StrUtil.format(\"{};charset={}\", contentType, charset));\n            httpHeaders.set(HttpHeaderNames.CONTENT_ENCODING.toString(), charset);\n        }\n\n\t\thttpHeaders.set(HttpHeaderNames.CONTENT_LENGTH.toString(), byteBuf.readableBytes());\n\n\t\t// Cookies\n\t\tfor (Cookie cookie : cookies) {\n\t\t\thttpHeaders.add(HttpHeaderNames.SET_COOKIE.toString(), ServerCookieEncoder.LAX.encode(cookie));\n\t\t}\n\n\t\treturn fullHttpResponse;\n\t}\n\t// -------------------------------------------------------------------------------------- build HttpResponse end\n\n\t// -------------------------------------------------------------------------------------- send start\n\t/**\n\t * 发送响应到客户端<br>\n\t * \n\t * @return ChannelFuture\n\t * @throws IOException \n\t */\n\tpublic ChannelFuture send() {\n\t\tChannelFuture channelFuture;\n\t\tif(content instanceof File){\n\t\t\t//文件\n\t\t\tFile file = (File)content;\n\t\t\ttry {\n\t\t\t\tchannelFuture = sendFile(file);\n\t\t\t} catch (IOException e) {\n                Logger.error(StrUtil.format(\"Send {} error!\", file), e.toString());\n\t\t\t\tchannelFuture = sendError(HttpResponseStatus.FORBIDDEN, \"\");\n\t\t\t}\n\t\t}else{\n\t\t\t//普通文本\n\t\t\tchannelFuture = sendFull();\n\t\t}\n\t\t\n\t\tthis.isSent = true;\n\t\treturn channelFuture;\n\t}\n\t\n\t/**\n\t * @return 是否已经出发发送请求，内部使用<br>\n\t */\n\tprotected boolean isSent(){\n\t\treturn this.isSent;\n\t}\n\t\n\t/**\n\t * 发送响应到客户端\n\t * \n\t * @return ChannelFuture\n\t */\n\tprivate ChannelFuture sendFull() {\n\t\tif (request != null && request.isKeepAlive()) {\n\t\t\tsetKeepAlive();\n\t\t\treturn ctx.writeAndFlush(this.toFullHttpResponse());\n\t\t} else {\n\t\t\treturn sendAndCloseFull();\n\t\t}\n\t}\n\t\n\t/**\n\t * 发送给到客户端并关闭ChannelHandlerContext\n\t * \n\t * @return ChannelFuture\n\t */\n\tprivate ChannelFuture sendAndCloseFull() {\n\t\treturn ctx.writeAndFlush(this.toFullHttpResponse()).addListener(ChannelFutureListener.CLOSE);\n\t}\n\t\n\t/**\n\t * 发送文件\n\t * \n\t * @param file 文件\n\t * @return ChannelFuture\n\t * @throws IOException\n\t */\n\tprivate ChannelFuture sendFile(File file) throws IOException {\n\t\tfinal RandomAccessFile raf = new RandomAccessFile(file, \"r\");\n\t\t\n\t\t// 内容长度\n\t\tlong fileLength = raf.length();\n\t\tthis.setContentLength(fileLength);\n\t\t\n\t\t//文件类型\n        Tika tika = new Tika();\n        String contentType = tika.detect(file);\n//\t\tString contentType = HttpUtil.getMimeType(file.getName());\n\t\tif(StrUtil.isBlank(contentType)){\n\t\t\t//无法识别默认使用数据流\n\t\t\tcontentType = \"application/octet-stream\";\n\t\t}\n\t\tthis.setContentType(contentType);\n\t\t\n\t\tctx.write(this.toDefaultHttpResponse());\n\t\tctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise())\n\t\t\t.addListener(FileProgressiveFutureListener.build(raf));\n\t\t\n\t\treturn sendEmptyLast();\n\t}\n\t\n\t/**\n\t * 发送结尾标记，表示发送结束\n\t * @return ChannelFuture\n\t */\n\tprivate ChannelFuture sendEmptyLast(){\n\t\tfinal ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);\n\t\tif (false == request.isKeepAlive()) {\n\t\t\tlastContentFuture.addListener(ChannelFutureListener.CLOSE);\n\t\t}\n\t\t\n\t\treturn lastContentFuture;\n\t}\n\t// -------------------------------------------------------------------------------------- send end\n\n\t// ---------------------------------------------------------------------------- special response start\n\n\t/**\n\t * 302 重定向\n\t * \n\t * @param uri 重定向到的URI\n\t * @return ChannelFuture\n\t */\n\tpublic ChannelFuture sendRedirect(String uri) {\n\t\treturn this.setStatus(HttpResponseStatus.FOUND).setHeader(HttpHeaderNames.LOCATION.toString(), uri).send();\n\t}\n\n\t/**\n\t * 304 文件未修改\n\t * \n\t * @return ChannelFuture\n\t */\n\tpublic ChannelFuture sendNotModified() {\n\t\treturn this.setStatus(HttpResponseStatus.NOT_MODIFIED).setHeader(HttpHeaderNames.DATE.toString(), DateUtil.formatHttpDate(DateUtil.date())).send();\n\t}\n\n\t/**\n\t * 发送错误消息\n\t * \n\t * @param status 错误状态码\n\t * @param msg 消息内容\n\t * @return ChannelFuture\n\t */\n\tpublic ChannelFuture sendError(HttpResponseStatus status, String msg) {\n\t\tif (ctx.channel().isActive()) {\n\t\t\treturn this.setStatus(status).setContent(msg).send();\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 发送404 Not Found\n\t * \n\t * @param msg 消息内容\n\t * @return ChannelFuture\n\t */\n\tpublic ChannelFuture sendNotFound(String msg) {\n\t\treturn sendError(HttpResponseStatus.NOT_FOUND, msg);\n\t}\n\n\t/**\n\t * 发送500 Internal Server Error\n\t * \n\t * @param msg 消息内容\n\t * @return ChannelFuture\n\t */\n\tpublic ChannelFuture sendServerError(String msg) {\n\t\treturn sendError(HttpResponseStatus.INTERNAL_SERVER_ERROR, msg);\n\t}\n\n\t// ---------------------------------------------------------------------------- special response end\n\n\t@Override\n\tpublic String toString() {\n\t\tfinal StringBuilder sb = new StringBuilder();\n\t\tsb.append(\"headers:\\r\\n \");\n\t\tfor ( Entry<String, String> entry : headers.entries()) {\n\t\t\tsb.append(\"    \").append(entry.getKey()).append(\": \").append(entry.getValue()).append(\"\\r\\n\");\n\t\t}\n\t\tsb.append(\"content: \").append(StrUtil.str(content, CharsetUtil.UTF_8));\n\n\t\treturn sb.toString();\n\t}\n\n\t// ---------------------------------------------------------------------------- static method start\n\t/**\n\t * 构建Response对象\n\t * \n\t * @param ctx ChannelHandlerContext\n\t * @param request 请求对象\n\t * @return Response对象\n\t */\n\tprotected static Response build(ChannelHandlerContext ctx, Request request) {\n\t\treturn new Response(ctx, request);\n\t}\n\n\t/**\n\t * 构建Response对象，Request对象为空，将无法获得某些信息<br>\n\t * 1. 无法使用长连接\n\t * \n\t * @param ctx ChannelHandlerContext\n\t * @return Response对象\n\t */\n\tprotected static Response build(ChannelHandlerContext ctx) {\n\t\treturn new Response(ctx, null);\n\t}\n\t// ---------------------------------------------------------------------------- static method end\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/listener/FileProgressiveFutureListener.java",
    "content": "package com.xiaoleilu.loServer.listener;\n\nimport java.io.RandomAccessFile;\n\nimport cn.hutool.core.io.IoUtil;\nimport io.netty.channel.ChannelProgressiveFuture;\nimport io.netty.channel.ChannelProgressiveFutureListener;\nimport org.slf4j.LoggerFactory;\n\n/**\n * 文件进度指示监听\n * @author Looly\n *\n */\npublic class FileProgressiveFutureListener implements ChannelProgressiveFutureListener{\n    private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(FileProgressiveFutureListener.class);\n\t\n\tprivate RandomAccessFile raf;\n\t\n\tpublic FileProgressiveFutureListener(RandomAccessFile raf) {\n\t\tthis.raf = raf;\n\t}\n\n\t@Override\n\tpublic void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {\n        Logger.debug(\"Transfer progress: {} / {}\", progress, total);\n\t}\n\n\t@Override\n\tpublic void operationComplete(ChannelProgressiveFuture future) {\n\t\tIoUtil.close(raf);\n        Logger.debug(\"Transfer complete.\");\n\t}\n\n\t/**\n\t * 构建文件进度指示监听\n\t * @param raf RandomAccessFile\n\t * @return 文件进度指示监听\n\t */\n\tpublic static FileProgressiveFutureListener build(RandomAccessFile raf){\n\t\treturn new FileProgressiveFutureListener(raf);\n\t}\n}\n"
  },
  {
    "path": "broker/src/main/java/com/xiaoleilu/loServer/model/FriendData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage com.xiaoleilu.loServer.model;\n\nimport java.io.Serializable;\n\npublic class FriendData implements Serializable {\n    private String userId;\n    private String friendUid;\n    private String alias;\n    private String extra;\n    private int state;\n    private int blacked;\n    private long timestamp;\n\n\n    public FriendData(String userId, String friendUid, String alias, String extra, int state, int blacked, long timestamp) {\n        this.userId = userId;\n        this.friendUid = friendUid;\n        this.alias = alias;\n        this.extra = extra;\n        this.state = state;\n        this.blacked = blacked;\n        this.timestamp = timestamp;\n    }\n\n    public FriendData() {\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getFriendUid() {\n        return friendUid;\n    }\n\n    public void setFriendUid(String friendUid) {\n        this.friendUid = friendUid;\n    }\n\n    public String getAlias() {\n        return alias;\n    }\n\n    public void setAlias(String alias) {\n        this.alias = alias;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public int getState() {\n        return state;\n    }\n\n    public void setState(int state) {\n        this.state = state;\n    }\n\n    public int getBlacked() {\n        return blacked;\n    }\n\n    public void setBlacked(int blacked) {\n        this.blacked = blacked;\n    }\n\n    public long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(long timestamp) {\n        this.timestamp = timestamp;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/BrokerConstants.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette;\n\nimport java.io.File;\n\npublic final class BrokerConstants {\n\n    public static final String INTERCEPT_HANDLER_PROPERTY_NAME = \"intercept.handler\";\n    public static final String BROKER_INTERCEPTOR_THREAD_POOL_SIZE = \"intercept.thread_pool.size\";\n    public static final String PERSISTENT_STORE_PROPERTY_NAME = \"persistent_store\";\n    public static final String SERVER_IP_PROPERTY_NAME = \"server.ip\";\n    public static final String PORT_PROPERTY_NAME = \"port\";\n    public static final String HOST_PROPERTY_NAME = \"host\";\n    public static final String HTTP_SERVER_PORT = \"http_port\";\n    public static final String HTTP_LOCAL_PORT = \"local_port\";\n\n    public static final String ENCRYPT_AES256 = \"encrypt.use_aes256\";\n\n    public static final String HTTP_ADMIN_PORT = \"http.admin.port\";\n    public static final String DEFAULT_MOQUETTE_STORE_MAP_DB_FILENAME = \"moquette_store.mapdb\";\n    public static final String DEFAULT_PERSISTENT_PATH = System.getProperty(\"user.dir\") + File.separator\n            + DEFAULT_MOQUETTE_STORE_MAP_DB_FILENAME;\n    public static final String WSS_PORT_PROPERTY_NAME = \"secure_websocket_port\";\n    public static final String SSL_PORT_PROPERTY_NAME = \"ssl_port\";\n    public static final String JKS_PATH_PROPERTY_NAME = \"jks_path\";\n    public static final String KEY_STORE_PASSWORD_PROPERTY_NAME = \"key_store_password\";\n    public static final String KEY_MANAGER_PASSWORD_PROPERTY_NAME = \"key_manager_password\";\n    public static final String AUTHORIZATOR_CLASS_NAME = \"authorizator_class\";\n    public static final String DB_AUTHENTICATOR_DRIVER = \"authenticator.db.driver\";\n    public static final String DB_AUTHENTICATOR_URL = \"authenticator.db.url\";\n    public static final String DB_AUTHENTICATOR_QUERY = \"authenticator.db.query\";\n    public static final String DB_AUTHENTICATOR_DIGEST = \"authenticator.db.digest\";\n    public static final int PORT = 1883;\n    public static final String DISABLED_PORT_BIND = \"disabled\";\n    public static final String HOST = \"0.0.0.0\";\n    public static final String NEED_CLIENT_AUTH = \"need_client_auth\";\n    public static final String HAZELCAST_CLIENT_IP = \"hazelcast.client.ip\";\n    public static final String HAZELCAST_CLIENT_PORT = \"hazelcast.client.port\";\n    public static final String NETTY_SO_BACKLOG_PROPERTY_NAME = \"netty.so_backlog\";\n    public static final String NETTY_SO_REUSEADDR_PROPERTY_NAME = \"netty.so_reuseaddr\";\n    public static final String NETTY_TCP_NODELAY_PROPERTY_NAME = \"netty.tcp_nodelay\";\n    public static final String NETTY_SO_KEEPALIVE_PROPERTY_NAME = \"netty.so_keepalive\";\n    public static final String NETTY_CHANNEL_TIMEOUT_SECONDS_PROPERTY_NAME = \"netty.channel_timeout.seconds\";\n    public static final String NETTY_EPOLL_PROPERTY_NAME = \"netty.epoll\";\n\n    public static final String STORAGE_CLASS_NAME = \"storage_class\";\n\n    public static final String QINIU_SERVER_URL= \"qiniu.server_url\";\n\tpublic static final String QINIU_ACCESS_KEY = \"qiniu.access_key\";\n\tpublic static final String QINIU_SECRET_KEY = \"qiniu.secret_key\";\n\n    public static final String QINIU_BUCKET_GENERAL_NAME= \"qiniu.bucket_general_name\";\n    public static final String QINIU_BUCKET_GENERAL_DOMAIN = \"qiniu.bucket_general_domain\";\n    public static final String QINIU_BUCKET_IMAGE_NAME= \"qiniu.bucket_image_name\";\n    public static final String QINIU_BUCKET_IMAGE_DOMAIN = \"qiniu.bucket_image_domain\";\n    public static final String QINIU_BUCKET_VOICE_NAME= \"qiniu.bucket_voice_name\";\n    public static final String QINIU_BUCKET_VOICE_DOMAIN = \"qiniu.bucket_voice_domain\";\n    public static final String QINIU_BUCKET_VIDEO_NAME= \"qiniu.bucket_video_name\";\n    public static final String QINIU_BUCKET_VIDEO_DOMAIN = \"qiniu.bucket_video_domain\";\n    public static final String QINIU_BUCKET_FILE_NAME= \"qiniu.bucket_file_name\";\n    public static final String QINIU_BUCKET_FILE_DOMAIN = \"qiniu.bucket_file_domain\";\n    public static final String QINIU_BUCKET_STICKER_NAME= \"qiniu.bucket_sticker_name\";\n    public static final String QINIU_BUCKET_STICKER_DOMAIN = \"qiniu.bucket_sticker_domain\";\n    public static final String QINIU_BUCKET_MOMENTS_NAME= \"qiniu.bucket_moments_name\";\n    public static final String QINIU_BUCKET_MOMENTS_DOMAIN = \"qiniu.bucket_moments_domain\";\n    public static final String QINIU_BUCKET_PORTRAIT_NAME= \"qiniu.bucket_portrait_name\";\n    public static final String QINIU_BUCKET_PORTRAIT_DOMAIN = \"qiniu.bucket_portrait_domain\";\n    public static final String QINIU_BUCKET_FAVORITE_NAME= \"qiniu.bucket_favorite_name\";\n    public static final String QINIU_BUCKET_FAVORITE_DOMAIN = \"qiniu.bucket_favorite_domain\";\n    public static final String QINIU_BUCKET_CUSTOM1_NAME= \"qiniu.bucket_custom1_name\";\n    public static final String QINIU_BUCKET_CUSTOM1_DOMAIN = \"qiniu.bucket_custom1_domain\";\n    public static final String QINIU_BUCKET_CUSTOM2_NAME= \"qiniu.bucket_custom2_name\";\n    public static final String QINIU_BUCKET_CUSTOM2_DOMAIN = \"qiniu.bucket_custom2_domain\";\n    public static final String QINIU_BUCKET_CUSTOM3_NAME= \"qiniu.bucket_custom3_name\";\n    public static final String QINIU_BUCKET_CUSTOM3_DOMAIN = \"qiniu.bucket_custom3_domain\";\n    public static final String QINIU_BUCKET_PAN_NAME= \"qiniu.bucket_pan_name\";\n    public static final String QINIU_BUCKET_PAN_DOMAIN = \"qiniu.bucket_pan_domain\";\n\n\n    public static final String FILE_STORAGE_ROOT = \"local.media.storage.root\";\n    public static final String FILE_STORAGE_REMOTE_SERVER_URL = \"local.media.storage.remote_server_url\";\n\n    public static final String USER_QINIU = \"media.server.use_qiniu\";\n\n    public static final String PUSH_ANDROID_SERVER_ADDRESS = \"push.android.server.address\";\n    public static final String PUSH_IOS_SERVER_ADDRESS = \"push.ios.server.address\";\n    public static final String PUSH_HARMONY_SERVER_ADDRESS = \"push.harmony.server.address\";\n\n    public static final String MONITOR_Exception_Event_Address = \"monitor.exception_event_address\";\n\n\n    public static final String USER_ONLINE_STATUS_CALLBACK = \"user.online_status_callback\";\n\n    public static final String GROUP_INFO_UPDATE_CALLBACK = \"group.group_info_update_callback\";\n    public static final String GROUP_MEMBER_UPDATE_CALLBACK = \"group.group_member_update_callback\";\n    public static final String RELATION_UPDATE_CALLBACK = \"relation.relation_update_callback\";\n    public static final String USER_INFO_UPDATE_CALLBACK = \"user.user_info_update_callback\";\n\n\n    public static final String CHANNEL_INFO_UPDATE_CALLBACK = \"channel.channel_info_update_callback\";\n    public static final String CHATROOM_INFO_UPDATE_CALLBACK = \"chatroom.chatroom_info_update_callback\";\n    public static final String CHATROOM_MEMBER_UPDATE_CALLBACK = \"chatroom.chatroom_member_update_callback\";\n\n    public static final String HTTP_SERVER_SECRET_KEY = \"http.admin.secret_key\";\n    public static final String HTTP_SERVER_API_NO_CHECK_TIME = \"http.admin.no_check_time\";\n\n    public static final String TOKEN_SECRET_KEY = \"token.key\";\n    public static final String TOKEN_EXPIRE_TIME = \"token.expire_time\";\n\n    public static final String CONNECT_CLIENT_SIGNATURE_LIST = \"connect.client_signature_list\";\n    public static final String CONNECT_REJECT_EMPTY_SIGNATURE = \"connect.reject_empty_signature\";\n\n    public static final String ID_USE_UUID = \"id.use_uuid\";\n\n    public static final String EMBED_DB_PROPERTY_NAME = \"embed.db\";\n    public static final String DB_AUTO_CLEAN_HISTORY_MESSAGES = \"db.auto_clean_history_messages\";\n    public static final String H2DB_PATH = \"h2db.path\";\n\n\n    public static final String SENSITIVE_Filter_Type = \"sensitive.filter.type\";\n    public static final String SENSITIVE_Only_Message = \"sensitive.only_message\";\n    public static final String SENSITIVE_Remote_Server_URL = \"sensitive.remote_server_url\";\n    public static final String SENSITIVE_Remote_Message_Type = \"sensitive.remote_sensitive_message_type\";\n    public static final String SENSITIVE_Remote_Fail_When_Matched = \"sensitive.remote_fail_when_matched\";\n\n    public static final String MESSAGE_Forward_Url = \"message.forward.url\";\n    public static final String MESSAGE_Sensitive_Forward_Url = \"message.sensitive.forward.url\";\n    public static final String MESSAGE_Forward_Types = \"message.forward.types\";\n    public static final String MESSAGE_Forward_Exclude_Types = \"message.forward.exclude_types\";\n    public static final String MESSAGE_MentionMsg_Forward_Url = \"message.mentionmsg.forward.url\";\n    public static final String MESSAGE_RecallMsg_Forward_Url = \"message.recallmsg.forward.url\";\n\n    public static final String SERVER_MULTI_ENDPOINT = \"server.multi_endpoint\";\n    public static final String SERVER_MULTI_PC_ENDPOINT = \"server.multi_pc_endpoint\";\n    public static final String SERVER_MULTI_PAD_ENDPOINT = \"server.multi_pad_endpoint\";\n    public static final String SERVER_MULTI_WEARABLE_ENDPOINT = \"server.multi_wearable_endpoint\";\n    public static final String SERVER_MULTI_TV_ENDPOINT = \"server.multi_tv_endpoint\";\n    public static final String SERVER_MULTI_PLATFROM_NOTIFICATION = \"server.multi_platform_notification\";\n    public static final String SERVER_MOBILE_DEFAULT_SILENT_WHEN_PC_ONLINE = \"server.mobile_default_silent_when_pc_online\";\n    public static final String SERVER_CLIENT_SUPPORT_KICKOFF_EVENT = \"server.client_support_kickoff_event\";\n\n    public static final String MESSAGE_ROAMING = \"message.roaming\";\n    public static final String MESSAGE_Compensate_Time_Limit = \"message.compensate_time_limit\";\n    public static final String MESSAGE_Remote_History_Message = \"message.remote_history_message\";\n    public static final String MESSAGE_Remote_Chatroom_History_Message = \"message.chatroom_remote_history_message\";\n\n    public static final String MESSAGE_Max_Queue = \"message.max_queue\";\n\n    public static final String MESSAGE_Disable_Stranger_Chat = \"message.disable_stranger_chat\";\n    public static final String MESSAGE_Allow_Stranger_Chat_List = \"message.allow_stranger_chat_list\";\n    public static final String MESSAGE_Allow_Stranger_Line = \"message.allow_stranger_line\";\n\n    public static final String MESSAGE_Blacklist_Strategy = \"message.blacklist.strategy\";\n    public static final String MESSAGE_Blacklist_Allow_Send = \"message.blacklist.allow_send_to_black\";\n\n    public static final String MESSAGE_NO_Forward_Admin_Message = \"message.no_forward_admin_message\";\n\n    public static final String MESSAGE_Push_Expired_Days = \"message.push_expired_days\";\n    public static final String MESSAGE_Force_Push_Types = \"message.force_push_types\";\n\n    public static final String MESSAGE_Forward_With_Client_Info = \"message.forward_with_client_info\";\n    public static final String MESSAGE_Forward_With_Sender_Info = \"message.forward_with_sender_info\";\n    public static final String MESSAGE_Forward_With_Target_Info = \"message.forward_with_target_info\";\n\n    public static final String BROADCAST_Target_From_User_Table = \"message.broadcast.target_from_user_table\";\n\n    public static final String MESSAGES_ALLOW_SEND_TO_FORBIDDEN_USER = \"message.allow_send_to_forbidden_user\";\n\n    public static final String ROBOT_Callback_With_Client_Info = \"robot.callback_with_client_info\";\n    public static final String ROBOT_Callback_With_Sender_Info = \"robot.callback_with_sender_info\";\n    public static final String ROBOT_Callback_With_Target_Info = \"robot.callback_with_target_info\";\n    public static final String ROBOT_Mention_External_Robot = \"robot.mention_external_robot\";\n    public static final String ROBOT_Get_User_Info_Mask = \"robot.get_user_info_mask\";\n\n    public static final String CHANNEL_Callback_With_Client_Info = \"channel.callback_with_client_info\";\n    public static final String CHANNEL_Callback_With_Sender_Info = \"channel.callback_with_sender_info\";\n    public static final String CHANNEL_Callback_With_Target_Info = \"channel.callback_with_target_info\";\n    public static final String CHANNEL_New_Callback_Feature = \"channel.new_callback_feature\";\n\n\n    public static final String FRIEND_Disable_Search = \"friend.disable_search\";\n    public static final String FRIEND_Disable_NickName_Search = \"friend.disable_nick_name_search\";\n    public static final String FRIEND_Disable_UserId_Search = \"friend.disable_user_id_search\";\n    public static final String FRIEND_Disable_Friend_Request = \"friend.disable_friend_request\";\n    public static final String FRIEND_Repeat_Request_Duration = \"friend.repeat_request_duration\";\n    public static final String FRIEND_Reject_Request_Duration = \"friend.reject_request_duration\";\n    public static final String FRIEND_Request_Expiration_Duration = \"friend.request_expiration_duration\";\n    public static final String FRIEND_Request_Rate_Limit = \"friend.request_rate_limit\";\n    public static final String FRIEND_Search_Mobile_Empty_Rate_Limit = \"friend.search_mobile_empty_rate_limit\";\n    public static final String FRIEND_Search_Rate_Limit = \"friend.search_rate_limit\";\n    public static final String FRIEND_Request_Robot_Auto_Accept = \"friend.robot_auto_accept\";\n\n\n    public static final String CHATROOM_Participant_Idle_Time = \"chatroom.participant_idle_time\";\n    public static final String CHATROOM_Rejoin_When_Active = \"chatroom.rejoin_when_active\";\n    public static final String CHATROOM_Create_When_Not_Exist = \"chatroom.create_when_not_exist\";\n    public static final String CHATROOM_Kickoff_Other_Platform = \"chatroom.kickoff_other_platform\";\n\n    public static final String GROUP_Allow_Owner_Recall_Self_Msg = \"group.allow_owner_recall_self_msg\";\n    public static final String GROUP_Allow_Manager_Recall_Self_Msg = \"group.allow_manager_recall_self_msg\";\n    public static final String GROUP_Allow_Client_Custom_Operation_Notification = \"group.allow_client_custom_operation_notification\";\n    public static final String GROUP_Allow_Robot_Custom_Operation_Notification = \"group.allow_robot_custom_operation_notificatio\";\n\n    public static final String GROUP_Visible_Quit_Kickoff_Notification = \"group.visible_quit_or_kickoff_notification\";\n    public static final String GROUP_Forbidden_Client_Operation = \"group.forbidden_client_operation\";\n\n    public static final String GROUP_Disable_Stranger_Invite = \"group.disable_stranger_invite\";\n    public static final String GROUP_ADD_MEMBER_ALLOW_PART_SUCCESS = \"group.add_member_allow_part_success\";\n\n    public static final String GROUP_INFO_MARK_DELETION = \"group.enable_mark_deletion\";\n\n    public static final String USER_HIDE_PROPERTIES = \"user.hide_properties\";\n    public static final String USER_KEEP_DISPLAY_NAME_WHEN_DESTROY = \"user.keep_display_name_when_destroy\";\n    public static final String USER_KEEP_FULL_INFO_WHEN_DESTROY = \"user.keep_full_info_when_destroy\";\n    public static final String USER_KEEP_MOBILE_WHEN_DESTROY = \"user.keep_mobile_when_destroy\";\n    public static final String USER_KEEP_MESSAGES_WHEN_DESTROY = \"user.keep_messages_when_destroy\";\n\n    public static final String SYNC_Data_Part_Size = \"sync.data_part_size\";\n\n    public static final String MESSAGES_FORBIDDEN_CLIENT_SEND_TYPES = \"message.forbidden_client_send_types\";\n    public static final String MESSAGES_BLACKLIST_EXCEPTION_TYPES = \"message.blacklist_exception_types\";\n    public static final String MESSAGES_GROUP_MUTE_EXCEPTION_TYPES = \"message.group_mute_exception_types\";\n    public static final String MESSAGES_GLOBAL_MUTE_EXCEPTION_TYPES = \"message.global_mute_exception_types\";\n\n    public static final String MESSAGES_DISABLE_REMOTE_SEARCH = \"message.disable_remote_search\";\n    public static final String MESSAGES_ENCRYPT_MESSAGE_CONTENT = \"message.encrypt_message_content\";\n\n\n    public static final String MESSAGES_RECALL_TIME_LIMIT = \"message.recall_time_limit\";\n    public static final String MESSAGES_DISABLE_GROUP_MANAGER_RECALL = \"message.disable_group_manager_recall\";\n\n    public static final String HTTP_ADMIN_RATE_LIMIT = \"http.admin.rate_limit\";\n    public static final String HTTP_ROBOT_RATE_LIMIT = \"http.robot.rate_limit\";\n    public static final String HTTP_CHANNEL_RATE_LIMIT = \"http.channel.rate_limit\";\n    public static final String CLIENT_REQUEST_RATE_LIMIT = \"client.request_rate_limit\";\n\n    public static final String HTTP_CLOSE_API_VERSION = \"http.close_api_version\";\n\n\n    private BrokerConstants() {\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/connections/IConnectionsManager.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.connections;\n\nimport java.util.Collection;\n\n/**\n * This interface will be used by an external codebase to retrieve and close physical connections.\n */\npublic interface IConnectionsManager {\n\n    /**\n     * Returns the number of physical connections\n     *\n     * @return\n     */\n    int getActiveConnectionsNo();\n\n    /**\n     * Determines wether a MQTT client is connected to the broker.\n     *\n     * @param clientID\n     * @return\n     */\n    boolean isConnected(String clientID);\n\n    /**\n     * Returns the identifiers of the MQTT clients that are connected to the broker.\n     *\n     * @return\n     */\n    Collection<String> getConnectedClientIds();\n\n    /**\n     * Closes a physical connection.\n     *\n     * @param clientID\n     * @param closeImmediately\n     *            If false, the connection will be flushed before it is closed.\n     * @return\n     */\n    boolean closeConnection(String clientID, boolean closeImmediately);\n\n    /**\n     * Returns the state of the session of a given client.\n     *\n     * @param clientID\n     * @return\n     */\n    MqttSession getSessionStatus(String clientID);\n\n    /**\n     * Returns the state of all the sessions\n     *\n     * @return\n     */\n    Collection<MqttSession> getSessions();\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/connections/MqttConnectionMetrics.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.connections;\n\n/**\n * A class that represents the metrics of a given MQTT connection.\n */\npublic class MqttConnectionMetrics {\n\n    private long readKb;\n    private long writtenKb;\n    private long readMessages;\n    private long writtenMessages;\n\n    public MqttConnectionMetrics(long readBytes, long writtenBytes, long readMessages, long writtenMessages) {\n        this.readKb = readBytes / 1024;\n        this.writtenKb = writtenBytes / 1024;\n        this.readMessages = readMessages;\n        this.writtenMessages = writtenMessages;\n    }\n\n    public long getReadKb() {\n        return readKb;\n    }\n\n    public long getWrittenKb() {\n        return writtenKb;\n    }\n\n    public long getReadMessages() {\n        return readMessages;\n    }\n\n    public long getWrittenMessages() {\n        return writtenMessages;\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/connections/MqttSession.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.connections;\n\nimport java.util.Collection;\n\n/**\n * A class that represents the overall connection status of a MQTT session. Its instances will be\n * used by an external codebase when the broker is configured in embedded mode.\n */\npublic class MqttSession {\n\n    private boolean connectionEstablished;\n    private boolean cleanSession;\n    private int inflightMessages;\n    private int pendingPublishMessagesNo;\n    private int secondPhaseAckPendingMessages;\n    private MqttConnectionMetrics connectionMetrics;\n\n    public boolean isConnectionEstablished() {\n        return connectionEstablished;\n    }\n\n    public void setConnectionEstablished(boolean connectionEstablished) {\n        this.connectionEstablished = connectionEstablished;\n    }\n\n    public boolean isCleanSession() {\n        return cleanSession;\n    }\n\n    public void setCleanSession(boolean cleanSession) {\n        this.cleanSession = cleanSession;\n    }\n\n    public int getPendingPublishMessagesNo() {\n        return pendingPublishMessagesNo;\n    }\n\n    public void setPendingPublishMessagesNo(int pendingPublishMessagesNo) {\n        this.pendingPublishMessagesNo = pendingPublishMessagesNo;\n    }\n\n    public int getInflightMessages() {\n        return inflightMessages;\n    }\n\n    public void setInflightMessages(int inflightMessages) {\n        this.inflightMessages = inflightMessages;\n    }\n\n    public int getSecondPhaseAckPendingMessages() {\n        return secondPhaseAckPendingMessages;\n    }\n\n    public void setSecondPhaseAckPendingMessages(int secondPhaseAckPendingMessages) {\n        this.secondPhaseAckPendingMessages = secondPhaseAckPendingMessages;\n    }\n\n    public MqttConnectionMetrics getConnectionMetrics() {\n        return connectionMetrics;\n    }\n\n    public void setConnectionMetrics(MqttConnectionMetrics connectionMetrics) {\n        this.connectionMetrics = connectionMetrics;\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/AddFriendHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\nimport static win.liyufan.im.IMTopic.HandleFriendRequestTopic;\n\n@Handler(IMTopic.AddFriendRequestTopic)\npublic class AddFriendHandler extends GroupHandler<WFCMessage.AddFriendRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.AddFriendRequest request, Qos1PublishHandler.IMCallback callback) {\n            long[] head = new long[1];\n            boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n            boolean isRobot = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot;\n            ErrorCode errorCode = m_messagesStore.saveAddFriendRequest(fromUser, request, head, isAdmin, isRobot);\n            if (errorCode == ERROR_CODE_SUCCESS) {\n                WFCMessage.User user = m_messagesStore.getUserInfo(request.getTargetUid());\n                if (user != null && user.getType() == ProtoConstants.UserType.UserType_Normal) {\n                    publisher.publishNotification(IMTopic.NotifyFriendRequestTopic, request.getTargetUid(), head[0], fromUser, request.getReason());\n                } else if(user != null && user.getType() == ProtoConstants.UserType.UserType_Robot) {\n                    if(m_messagesStore.isRobotAutoAcceptFriendRequest()) {\n                        WFCMessage.HandleFriendRequest handleFriendRequest = WFCMessage.HandleFriendRequest.newBuilder().setTargetUid(fromUser).setStatus(ProtoConstants.FriendRequestStatus.RequestStatus_Accepted).build();\n                        mServer.onApiMessage(request.getTargetUid(), null, handleFriendRequest.toByteArray(), 0, fromUser, HandleFriendRequestTopic, requestSourceType);\n                    }\n                }\n            }\n            return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/AddGroupMember.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.pojos.GroupNotificationBinaryContent;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(value = IMTopic.AddGroupMemberTopic)\npublic class AddGroupMember extends GroupHandler<WFCMessage.AddGroupMemberRequest> {\n\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.AddGroupMemberRequest request, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n\n        if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {\n            int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();\n            if(request.getAddedMemberList().size() == 1 && request.getAddedMember(0).getMemberId().equals(fromUser)) {\n                if ((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Join_Group) > 0) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n            } else {\n                if ((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Invite_Group_Member) > 0) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n            }\n        }\n\n        Map<String, Integer> failedMembers = new HashMap<>();\n        if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {\n            ErrorCode errorCode = m_messagesStore.canAddGroupMembers(fromUser, request.getAddedMemberList(), failedMembers);\n            if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                return errorCode;\n            }\n        }\n\n        ErrorCode errorCode = m_messagesStore.addGroupMembers(fromUser, isAdmin, request.getGroupId(), request.getAddedMemberList(), request.getExtra(), failedMembers);\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());\n            } else {\n                List<String> added = getMemberIdList(request.getAddedMemberList());\n                added.removeAll(failedMembers.keySet());\n                WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, added).setExtra(request.getExtra()).getAddGroupNotifyContent();\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);\n            }\n        }\n\n        if (errorCode == ERROR_CODE_SUCCESS && !failedMembers.isEmpty()) {\n            WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, \"\").setMi(failedMembers).getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_REJECT_JOIN_GROUP);\n            sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);\n        }\n\n        if(errorCode == ERROR_CODE_SUCCESS && !failedMembers.isEmpty()) {\n            return ErrorCode.ERROR_CODE_PARTLY_SUCCESS;\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/BlackListRequestHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.BlackListUserTopic)\npublic class BlackListRequestHandler extends GroupHandler<WFCMessage.BlackUserRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.BlackUserRequest request, Qos1PublishHandler.IMCallback callback) {\n        long[] head = new long[1];\n        ErrorCode errorCode = m_messagesStore.blackUserRequest(fromUser, request.getUid(), request.getStatus(), head);\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            publisher.publishNotification(IMTopic.NotifyFriendTopic, fromUser, head[0]);\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/BroadcastMessageHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.BrokerConstants;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\nimport win.liyufan.im.MessageShardingUtil;\n\nimport java.util.Set;\n\nimport static cn.wildfirechat.proto.ProtoConstants.ContentType.Text;\n\n@Handler(value = IMTopic.BroadcastMessageTopic)\npublic class BroadcastMessageHandler extends IMHandler<WFCMessage.Message> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.Message message, Qos1PublishHandler.IMCallback callback) {\n        ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        if (message != null) {\n            if (!isAdmin) {  //only admin can broadcast message\n                return ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n\n            long timestamp = System.currentTimeMillis();\n            long messageId = 0;\n            try {\n                messageId = MessageShardingUtil.generateId();\n            } catch (Exception e) {\n                e.printStackTrace();\n                return ErrorCode.ERROR_CODE_SERVER_ERROR;\n            }\n            message = message.toBuilder().setFromUser(fromUser).setMessageId(messageId).setServerTimestamp(timestamp).setConversation(WFCMessage.Conversation.newBuilder().setTarget(fromUser).setLine(message.getConversation().getLine()).setType(ProtoConstants.ConversationType.ConversationType_Private).build()).build();\n\n            long count = saveAndBroadcast(fromUser, clientID, message);\n            ackPayload = ackPayload.capacity(20);\n            ackPayload.writeLong(messageId);\n            ackPayload.writeLong(count);\n        } else {\n            errorCode = ErrorCode.ERROR_CODE_INVALID_MESSAGE;\n        }\n        return errorCode;\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/ChannelListenMember.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport static win.liyufan.im.IMTopic.PutUserSettingTopic;\nimport static win.liyufan.im.UserSettingScope.kUserSettingListenedChannels;\n\n@Handler(value = IMTopic.ChannelListenTopic)\npublic class ChannelListenMember extends IMHandler<WFCMessage.ListenChannel> {\n\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.ListenChannel request, Qos1PublishHandler.IMCallback callback) {\n        ErrorCode errorCode = m_messagesStore.listenChannel(fromUser, request.getChannelId(), request.getListen()>0);\n        if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n            WFCMessage.ModifyUserSettingReq modifyUserSettingReq = WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingListenedChannels).setKey(request.getChannelId()).setValue(request.getListen() > 0 ? \"1\" : \"0\").build();\n            mServer.onApiMessage(fromUser, null, modifyUserSettingReq.toByteArray(), 0, fromUser, PutUserSettingTopic, requestSourceType);\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/ChannelListenedListHandler.java",
    "content": "package io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.List;\n\n@Handler(IMTopic.ListenedChannelListTopic)\npublic class ChannelListenedListHandler extends IMHandler<Void> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, Void request, Qos1PublishHandler.IMCallback callback) {\n        List<String> channelInfoList = m_messagesStore.getListenedChannels(fromUser);\n        WFCMessage.IDListBuf.Builder builder = WFCMessage.IDListBuf.newBuilder();\n        builder.addAllId(channelInfoList);\n        byte[] data = builder.build().toByteArray();\n        ackPayload.ensureWritable(data.length).writeBytes(data);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/ChannelSearchHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.List;\n\n@Handler(IMTopic.ChannelSearchTopic)\npublic class ChannelSearchHandler extends IMHandler<WFCMessage.SearchUserRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.SearchUserRequest request, Qos1PublishHandler.IMCallback callback) {\n        List<WFCMessage.ChannelInfo> users = m_messagesStore.searchChannel(request.getKeyword(), request.getFuzzy() > 0, request.getPage());\n        WFCMessage.SearchChannelResult.Builder builder = WFCMessage.SearchChannelResult.newBuilder();\n        builder.addAllChannel(users);\n        builder.setKeyword(request.getKeyword());\n        byte[] data = builder.build().toByteArray();\n        ackPayload.ensureWritable(data.length).writeBytes(data);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/ConfigApplicationHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.ApplicationConfigRequestTopic)\npublic class ConfigApplicationHandler extends IMHandler<WFCMessage.ApplicationConfigRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.ApplicationConfigRequest request, Qos1PublishHandler.IMCallback callback) {\n        ErrorCode errorCode = m_messagesStore.configApplication(request.getAppId(), request.getAppType(), request.getTimestamp(), request.getNonce(), request.getSignature());\n        return errorCode;\n    }\n}\n\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/CreateChannelHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.proto.ProtoConstants.RequestSourceType.Request_From_Admin;\nimport static win.liyufan.im.IMTopic.PutUserSettingTopic;\nimport static win.liyufan.im.UserSettingScope.kUserSettingMyChannels;\n\n@Handler(value = IMTopic.CreateChannelTopic)\npublic class CreateChannelHandler extends GroupHandler<WFCMessage.ChannelInfo> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.ChannelInfo request, Qos1PublishHandler.IMCallback callback) {\n        WFCMessage.ChannelInfo.Builder builder = request.toBuilder();\n        if (StringUtil.isNullOrEmpty(request.getTargetId())) {\n            builder.setTargetId(m_messagesStore.getShortUUID());\n        }\n        if (StringUtil.isNullOrEmpty(request.getOwner())) {\n            builder.setOwner(fromUser);\n        }\n        if (StringUtil.isNullOrEmpty(request.getSecret())) {\n            builder.setSecret(m_messagesStore.getShortUUID());\n        }\n\n        long update = System.currentTimeMillis();\n        request = builder.setUpdateDt(update).build();\n\n        ErrorCode errorCode = m_messagesStore.createChannel(fromUser, request);\n\n        if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n            WFCMessage.ModifyUserSettingReq modifyUserSettingReq = WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingMyChannels).setKey(request.getTargetId()).setValue(\"1\").build();\n            mServer.onApiMessage(fromUser, null, modifyUserSettingReq.toByteArray(), 0, fromUser, PutUserSettingTopic, requestSourceType);\n            byte[] data;\n            if (requestSourceType == Request_From_Admin) {\n                //When server api create channel, need return channelId and secret together.\n                data = (request.getTargetId() + \"|\" + request.getSecret()).getBytes();\n            } else {\n                data = request.getTargetId().getBytes();\n            }\n            ackPayload.ensureWritable(data.length).writeBytes(data);\n            return ErrorCode.ERROR_CODE_SUCCESS;\n        } else {\n            return errorCode;\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/CreateGroupHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.pojos.GroupNotificationBinaryContent;\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n@Handler(value = IMTopic.CreateGroupTopic)\npublic class CreateGroupHandler extends GroupHandler<WFCMessage.CreateGroupRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.CreateGroupRequest request, Qos1PublishHandler.IMCallback callback) {\n        if(request.getGroup().getGroupInfo().getType() < 0 || request.getGroup().getGroupInfo().getType() > 3) {\n            return ErrorCode.ERROR_CODE_INVALID_DATA;\n        }\n\n        if (!StringUtil.isNullOrEmpty(request.getGroup().getGroupInfo().getTargetId())) {\n            WFCMessage.GroupInfo existGroupInfo = m_messagesStore.getGroupInfo(request.getGroup().getGroupInfo().getTargetId());\n            if (existGroupInfo != null && existGroupInfo.getDeleted() == 0) {\n                return ErrorCode.ERROR_CODE_GROUP_ALREADY_EXIST;\n            }\n        }\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !m_messagesStore.isAllowClientCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot && !m_messagesStore.isAllowRobotCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if(!isAdmin && request.getGroup().getGroupInfo().getType() == ProtoConstants.GroupType.GroupType_Organization) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {\n            int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();\n            if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Create_Group) > 0) {\n                return ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n        }\n\n        Map<String, Integer> failedMembers = new HashMap<>();\n        if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {\n            ErrorCode errorCode = m_messagesStore.canAddGroupMembers(fromUser, request.getGroup().getMembersList(), failedMembers);\n            if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                return errorCode;\n            }\n        }\n\n        if (request.getGroup().getGroupInfo().getTargetId().length() > 64\n            || request.getGroup().getGroupInfo().getName().length() > 64\n            || request.getGroup().getGroupInfo().getPortrait().length() > 1024) {\n            return ErrorCode.INVALID_PARAMETER;\n        }\n\n        if(!isAdmin && !StringUtil.isNullOrEmpty(request.getGroup().getGroupInfo().getName())) {\n            if(!m_messagesStore.isSensitiveOnlyMessage()) {\n                Set<String> matched = m_messagesStore.handleSensitiveWord(request.getGroup().getGroupInfo().getName());\n                if (matched != null && !matched.isEmpty()) {\n                    return ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;\n                }\n            }\n\n            if(!m_messagesStore.isAllowName(request.getGroup().getGroupInfo().getName())) {\n                return ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n        }\n\n        WFCMessage.GroupInfo groupInfo = m_messagesStore.createGroup(fromUser, request.getGroup().getGroupInfo(), request.getGroup().getMembersList(), request.getMemberExtra(), isAdmin, failedMembers);\n        if (groupInfo != null && groupInfo.getDeleted() == 0) {\n            if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {\n                sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), request.getNotifyContent());\n            } else {\n                WFCMessage.MessageContent content = new GroupNotificationBinaryContent(groupInfo.getTargetId(), fromUser, groupInfo.getName(), \"\").setExtra(request.getMemberExtra()).getCreateGroupNotifyContent();\n                sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), content);\n            }\n\n            if(!failedMembers.isEmpty()) {\n                WFCMessage.MessageContent content = new GroupNotificationBinaryContent(groupInfo.getTargetId(), fromUser, null, \"\").setMi(failedMembers).getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_REJECT_JOIN_GROUP);\n                sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), content);\n            }\n        }\n\n        byte[] data = groupInfo.getTargetId().getBytes();\n        ackPayload.ensureWritable(data.length).writeBytes(data);\n        if(failedMembers.isEmpty()) {\n            return ErrorCode.ERROR_CODE_SUCCESS;\n        } else {\n            return ErrorCode.ERROR_CODE_PARTLY_SUCCESS;\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/DeleteFriendHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.DeleteFriendTopic)\npublic class DeleteFriendHandler extends IMHandler<WFCMessage.IDBuf> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.IDBuf request, Qos1PublishHandler.IMCallback callback) {\n        long[] head = new long[2];\n        ErrorCode errorCode = m_messagesStore.deleteFriend(fromUser, request.getId(), head);\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            publisher.publishNotification(IMTopic.NotifyFriendTopic, fromUser, head[0]);\n            publisher.publishNotification(IMTopic.NotifyFriendTopic, request.getId(), head[1]);\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/DestroyChannelHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport static win.liyufan.im.IMTopic.PutUserSettingTopic;\nimport static win.liyufan.im.UserSettingScope.kUserSettingMyChannels;\n\n@Handler(value = IMTopic.DestroyChannelInfoTopic)\npublic class DestroyChannelHandler extends GroupHandler<WFCMessage.IDBuf> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.IDBuf request, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        ErrorCode errorCode = m_messagesStore.destroyChannel(fromUser, request.getId(), isAdmin);\n        if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n            WFCMessage.ModifyUserSettingReq modifyUserSettingReq = WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingMyChannels).setKey(request.getId()).setValue(\"0\").build();\n            mServer.onApiMessage(fromUser, null, modifyUserSettingReq.toByteArray(), 0, fromUser, PutUserSettingTopic, requestSourceType);\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/DestroyUserHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\n\n@Handler(IMTopic.DestroyUserTopic)\npublic class DestroyUserHandler extends IMHandler<WFCMessage.IDBuf> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.IDBuf request, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        if (isAdmin) {\n            mServer.getImBusinessScheduler().execute(()-> {\n                m_sessionsStore.clearUserSession(fromUser);\n                m_messagesStore.clearUserMessages(fromUser);\n                m_messagesStore.clearUserSettings(fromUser);\n                m_messagesStore.clearUserFriend(fromUser);\n                m_messagesStore.clearUserGroups(fromUser);\n                m_messagesStore.clearUserChannels(fromUser);\n                m_messagesStore.destroyUser(fromUser);\n\n                m_messagesStore.destroyRobot(fromUser);\n            });\n            return ErrorCode.ERROR_CODE_SUCCESS;\n        } else {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/DisconnectHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.model.FriendData;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.List;\n\n@Handler(value = IMTopic.ClearSessionTopic)\npublic class DisconnectHandler extends IMHandler<Byte> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, Byte request, Qos1PublishHandler.IMCallback callback) {\n        if (request == 8) {\n            m_sessionsStore.cleanSession(fromUser, clientID);\n        } else if(request == 1) {\n            m_sessionsStore.disableSession(fromUser, clientID);\n        }\n\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/DismissGroupHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.pojos.GroupNotificationBinaryContent;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\n\nimport static win.liyufan.im.IMTopic.DismissGroupTopic;\n\n@Handler(value = DismissGroupTopic)\npublic class DismissGroupHandler extends GroupHandler<WFCMessage.DismissGroupRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.DismissGroupRequest request, Qos1PublishHandler.IMCallback callback) {\n            WFCMessage.GroupInfo groupInfo = m_messagesStore.getGroupInfo(request.getGroupId());\n            boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n            ErrorCode errorCode;\n            if (groupInfo == null) {\n                errorCode = m_messagesStore.dismissGroup(fromUser, request.getGroupId(), isAdmin);\n            } else if (isAdmin || (groupInfo.getType() == ProtoConstants.GroupType.GroupType_Normal || groupInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted)\n                && groupInfo.getOwner() != null && groupInfo.getOwner().equals(fromUser)) {\n\n                if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !m_messagesStore.isAllowClientCustomGroupNotification()) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n\n                if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot && !m_messagesStore.isAllowRobotCustomGroupNotification()) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n\n                if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {\n                    int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();\n                    if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Dismiss_Group) > 0) {\n                        return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                    }\n                }\n\n                //send notify message first, then dismiss group\n                if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {\n                    sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), request.getNotifyContent());\n                } else {\n                    WFCMessage.MessageContent content = new GroupNotificationBinaryContent(groupInfo.getTargetId(), fromUser, null, \"\").getDismissGroupNotifyContent();\n                    sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);\n                }\n                errorCode = m_messagesStore.dismissGroup(fromUser, request.getGroupId(), isAdmin);\n            } else {\n                errorCode = ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n            return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/FriendPullHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.model.FriendData;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.List;\n\n@Handler(IMTopic.FriendPullTopic)\npublic class FriendPullHandler extends IMHandler<WFCMessage.Version> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.Version request, Qos1PublishHandler.IMCallback callback) {\n        List<FriendData> friendDatas = m_messagesStore.getFriendList(fromUser, clientID, request.getVersion());\n        WFCMessage.GetFriendsResult.Builder builder = WFCMessage.GetFriendsResult.newBuilder();\n        for (FriendData data : friendDatas\n            ) {\n            WFCMessage.Friend.Builder builder1 = WFCMessage.Friend.newBuilder().setState(data.getState()).setBlacked(data.getBlacked()).setUid(data.getFriendUid()).setUpdateDt(data.getTimestamp());\n            if (!StringUtil.isNullOrEmpty(data.getAlias())) {\n                builder1.setAlias(data.getAlias());\n            }\n            if (!StringUtil.isNullOrEmpty(data.getExtra())) {\n                builder1.setExtra(data.getExtra());\n            }\n            builder.addEntry(builder1.build());\n        }\n        byte[] data = builder.build().toByteArray();\n        ackPayload.ensureWritable(data.length).writeBytes(data);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/FriendRequestPullHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.List;\n\n@Handler(IMTopic.FriendRequestPullTopic)\npublic class FriendRequestPullHandler extends IMHandler<WFCMessage.Version> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.Version request, Qos1PublishHandler.IMCallback callback) {\n            List<WFCMessage.FriendRequest> friendDatas = m_messagesStore.getFriendRequestList(fromUser, request.getVersion());\n            WFCMessage.GetFriendRequestResult.Builder builder = WFCMessage.GetFriendRequestResult.newBuilder();\n            builder.addAllEntry(friendDatas);\n            byte[] data = builder.build().toByteArray();\n            ackPayload.ensureWritable(data.length).writeBytes(data);\n            return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetApplicationTokenHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.GetApplicationTokenRequestTopic)\npublic class GetApplicationTokenHandler extends IMHandler<WFCMessage.AuthCodeRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.AuthCodeRequest request, Qos1PublishHandler.IMCallback callback) {\n        String authCode = m_messagesStore.getApplicationAuthCode(fromUser, request.getTargetId(), request.getType(), request.getHost());\n        if(authCode != null) {\n            byte[] data = WFCMessage.IDBuf.newBuilder().setId(authCode).build().toByteArray();\n            ackPayload.ensureWritable(data.length).writeBytes(data);\n            return ERROR_CODE_SUCCESS;\n        }\n        return ErrorCode.INVALID_PARAMETER;\n\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetChannelInfoHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Handler(IMTopic.ChannelPullTopic)\npublic class GetChannelInfoHandler extends IMHandler<WFCMessage.PullChannelInfo> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.PullChannelInfo request, Qos1PublishHandler.IMCallback callback) {\n        ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n        WFCMessage.ChannelInfo info = m_messagesStore.getChannelInfo(request.getChannelId());\n        if (info == null) {\n            errorCode = ErrorCode.ERROR_CODE_NOT_EXIST;\n        } else if(info.getUpdateDt() <= request.getHead()) {\n            errorCode = ErrorCode.ERROR_CODE_NOT_MODIFIED;\n        } else {\n            if (!info.getOwner().equals(fromUser)) {\n                info = info.toBuilder().clearCallback().clearSecret().build();\n            }\n\n            byte[] data = info.toByteArray();\n            ackPayload.ensureWritable(data.length).writeBytes(data);\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetChatroomInfoHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Handler(IMTopic.GetChatroomInfoTopic)\npublic class GetChatroomInfoHandler extends IMHandler<WFCMessage.GetChatroomInfoRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.GetChatroomInfoRequest request, Qos1PublishHandler.IMCallback callback) {\n        ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n        WFCMessage.ChatroomInfo info = m_messagesStore.getChatroomInfo(request.getChatroomId());\n        if (info == null) {\n            errorCode = ErrorCode.ERROR_CODE_NOT_EXIST;\n        } else if(info.getUpdateDt() <= request.getUpdateDt()) {\n            errorCode = ErrorCode.ERROR_CODE_NOT_MODIFIED;\n        } else {\n            int memberCount = m_messagesStore.getChatroomMemberCount(request.getChatroomId());\n            byte[] data = info.toBuilder().setMemberCount(memberCount).build().toByteArray();\n            ackPayload.ensureWritable(data.length).writeBytes(data);\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetChatroomMemberHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Handler(IMTopic.GetChatroomMemberTopic)\npublic class GetChatroomMemberHandler extends IMHandler<WFCMessage.GetChatroomMemberInfoRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.GetChatroomMemberInfoRequest request, Qos1PublishHandler.IMCallback callback) {\n        ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n            WFCMessage.ChatroomMemberInfo info = m_messagesStore.getChatroomMemberInfo(request.getChatroomId(), request.getMaxCount());\n            if (info != null) {\n                byte[] data = info.toByteArray();\n                ackPayload.ensureWritable(data.length).writeBytes(data);\n            } else {\n                errorCode = ErrorCode.ERROR_CODE_NOT_EXIST;\n            }\n            return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetCommonGroupsHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.Set;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.GetCommonGroupsTopic)\npublic class GetCommonGroupsHandler extends IMHandler<WFCMessage.IDBuf> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.IDBuf request, Qos1PublishHandler.IMCallback callback) {\n        WFCMessage.PullUserResult.Builder resultBuilder = WFCMessage.PullUserResult.newBuilder();\n        Set<String> strings = m_messagesStore.getCommonGroupIds(fromUser, request.getId());\n        WFCMessage.IDListBuf idListBuf = WFCMessage.IDListBuf.newBuilder().addAllId(strings).build();\n        byte[] data = idListBuf.toByteArray();\n        ackPayload.ensureWritable(data.length).writeBytes(data);\n        return ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetGroupInfoHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.List;\n\n@Handler(IMTopic.GetGroupInfoTopic)\npublic class GetGroupInfoHandler extends IMHandler<WFCMessage.PullUserRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.PullUserRequest request, Qos1PublishHandler.IMCallback callback) {\n            List<WFCMessage.GroupInfo> infos = m_messagesStore.getGroupInfos(request.getRequestList(), fromUser, requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin);\n\n            WFCMessage.PullGroupInfoResult result = WFCMessage.PullGroupInfoResult.newBuilder().addAllInfo(infos).build();\n            byte[] data = result.toByteArray();\n            ackPayload.ensureWritable(data.length).writeBytes(data);\n            return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetGroupMemberHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.GetGroupMemberTopic)\npublic class GetGroupMemberHandler extends IMHandler<WFCMessage.PullGroupMemberRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.PullGroupMemberRequest request, Qos1PublishHandler.IMCallback callback) {\n        List<WFCMessage.GroupMember> members = new ArrayList<>();\n        ErrorCode errorCode = m_messagesStore.getGroupMembers(fromUser, request.getTarget(), request.getHead(), members);\n\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            WFCMessage.PullGroupMemberResult result = WFCMessage.PullGroupMemberResult.newBuilder().addAllMember(members).build();\n            byte[] data = result.toByteArray();\n            ackPayload.ensureWritable(data.length).writeBytes(data);\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetMediaUploadTokenHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.util.StringUtil;\nimport com.qiniu.util.Auth;\nimport com.xiaoleilu.loServer.action.UploadFileAction;\nimport io.moquette.server.config.MediaServerConfig;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\n\nimport static io.moquette.server.config.MediaServerConfig.FILE_STROAGE_REMOTE_SERVER_URL;\n\n@Handler(\"GMUT\")\npublic class GetMediaUploadTokenHandler extends IMHandler<WFCMessage.GetUploadTokenRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.GetUploadTokenRequest request, Qos1PublishHandler.IMCallback callback) {\n        int type = request.getMediaType();\n\n        String token;\n\n        WFCMessage.GetUploadTokenResult.Builder resultBuilder = WFCMessage.GetUploadTokenResult.newBuilder();\n        if (MediaServerConfig.USER_QINIU) {\n            Auth auth = Auth.create(MediaServerConfig.QINIU_ACCESS_KEY, MediaServerConfig.QINIU_SECRET_KEY);\n\n            String bucketName;\n            String bucketDomain;\n            switch (type) {\n                case 0:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_GENERAL_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN;\n                    break;\n                case 1:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_IMAGE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_IMAGE_DOMAIN;\n                    break;\n                case 2:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_VOICE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_VOICE_DOMAIN;\n                    break;\n                case 3:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_VIDEO_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_VIDEO_DOMAIN;\n                    break;\n                case 4:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_FILE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_FILE_DOMAIN;\n                    break;\n                case 5:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_PORTRAIT_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_PORTRAIT_DOMAIN;\n                    break;\n                case 6:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_FAVORITE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_FAVORITE_DOMAIN;\n                    break;\n                case 7:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_STICKER_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_STICKER_DOMAIN;\n                    break;\n               case 8:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_MOMENTS_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_MOMENTS_DOMAIN;\n                    break;\n                case 9:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_CUSTOM1_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_CUSTOM1_DOMAIN;\n                    break;\n                case 10:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_CUSTOM2_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_CUSTOM2_DOMAIN;\n                    break;\n                case 11:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_CUSTOM3_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_CUSTOM3_DOMAIN;\n                    break;\n                case 12:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_PAN_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_PAN_DOMAIN;\n                    break;\n                default:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_GENERAL_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN;\n                    break;\n            }\n\n            token = auth.uploadToken(bucketName);\n            resultBuilder.setDomain(bucketDomain)\n                .setServer(MediaServerConfig.QINIU_SERVER_URL);\n            resultBuilder.setPort(80);\n        } else {\n            token = UploadFileAction.getToken(type);\n            if(StringUtil.isNullOrEmpty(MediaServerConfig.FILE_STROAGE_REMOTE_SERVER_URL)) {\n                resultBuilder.setDomain(\"http://\" + MediaServerConfig.SERVER_IP + \":\" + MediaServerConfig.HTTP_SERVER_PORT);\n            } else {\n                resultBuilder.setDomain(MediaServerConfig.FILE_STROAGE_REMOTE_SERVER_URL);\n            }\n            resultBuilder.setServer(MediaServerConfig.SERVER_IP);\n            resultBuilder.setPort(MediaServerConfig.HTTP_SERVER_PORT);\n        }\n\n        resultBuilder.setToken(token);\n\n        byte[] data = resultBuilder.buildPartial().toByteArray();\n        ackPayload.ensureWritable(data.length).writeBytes(data);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetMyGroupsHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.Set;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.GetMyGroupsTopic)\npublic class GetMyGroupsHandler extends IMHandler<Void> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, Void request, Qos1PublishHandler.IMCallback callback) {\n        WFCMessage.PullUserResult.Builder resultBuilder = WFCMessage.PullUserResult.newBuilder();\n        Set<String> strings = m_messagesStore.getUserGroupIds(fromUser);\n        WFCMessage.IDListBuf idListBuf = WFCMessage.IDListBuf.newBuilder().addAllId(strings).build();\n        byte[] data = idListBuf.toByteArray();\n        ackPayload.ensureWritable(data.length).writeBytes(data);\n        return ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetQiniuUploadTokenHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.qiniu.util.Auth;\nimport com.xiaoleilu.loServer.action.UploadFileAction;\nimport io.moquette.server.config.MediaServerConfig;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Handler(IMTopic.GetQiniuUploadTokenTopic)\npublic class GetQiniuUploadTokenHandler extends IMHandler<Byte> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, Byte request, Qos1PublishHandler.IMCallback callback) {\n        int type = request;\n        String token;\n\n        WFCMessage.GetUploadTokenResult.Builder resultBuilder = WFCMessage.GetUploadTokenResult.newBuilder();\n\n        if (MediaServerConfig.USER_QINIU) {\n            Auth auth = Auth.create(MediaServerConfig.QINIU_ACCESS_KEY, MediaServerConfig.QINIU_SECRET_KEY);\n\n//#Media_Type_GENERAL = 0,\n//#Media_Type_IMAGE = 1,\n//#Media_Type_VOICE = 2,\n//#Media_Type_VIDEO = 3,\n//#Media_Type_FILE = 4,\n//#Media_Type_PORTRAIT = 5,\n//#Media_Type_FAVORITE = 6\n\n            String bucketName;\n            String bucketDomain;\n            switch (type) {\n                case 0:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_GENERAL_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN;\n                    break;\n                case 1:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_IMAGE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_IMAGE_DOMAIN;\n                    break;\n                case 2:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_VOICE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_VOICE_DOMAIN;\n                    break;\n                case 3:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_VIDEO_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_VIDEO_DOMAIN;\n                    break;\n                case 4:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_FILE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_FILE_DOMAIN;\n                    break;\n                case 5:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_PORTRAIT_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_PORTRAIT_DOMAIN;\n                    break;\n                case 6:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_FAVORITE_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_FAVORITE_DOMAIN;\n                    break;\n                case 7:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_STICKER_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_STICKER_DOMAIN;\n                    break;\n                case 8:\n                     bucketName = MediaServerConfig.QINIU_BUCKET_MOMENTS_NAME;\n                     bucketDomain = MediaServerConfig.QINIU_BUCKET_MOMENTS_DOMAIN;\n                     break;\n                case 9:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_CUSTOM1_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_CUSTOM1_DOMAIN;\n                    break;\n                case 10:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_CUSTOM2_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_CUSTOM2_DOMAIN;\n                    break;\n                case 11:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_CUSTOM3_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_CUSTOM3_DOMAIN;\n                    break;\n                case 12:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_PAN_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_PAN_DOMAIN;\n                    break;\n                default:\n                    bucketName = MediaServerConfig.QINIU_BUCKET_GENERAL_NAME;\n                    bucketDomain = MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN;\n                    break;\n            }\n\n            token = auth.uploadToken(bucketName);\n            resultBuilder.setDomain(bucketDomain)\n                .setServer(MediaServerConfig.QINIU_SERVER_URL);\n            resultBuilder.setPort(80);\n        } else {\n            token = UploadFileAction.getToken(type);\n            resultBuilder.setDomain(\"http://\" + MediaServerConfig.SERVER_IP + \":\" + MediaServerConfig.HTTP_SERVER_PORT)\n                .setServer(MediaServerConfig.SERVER_IP);\n            resultBuilder.setPort(MediaServerConfig.HTTP_SERVER_PORT);\n        }\n\n        resultBuilder.setToken(token);\n\n        byte[] data = resultBuilder.buildPartial().toByteArray();\n        ackPayload.ensureWritable(data.length).writeBytes(data);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetTokenHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.moquette.spi.impl.security.TokenAuthenticator;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\nimport win.liyufan.im.UserSettingScope;\n\n@Handler(IMTopic.GetTokenTopic)\npublic class GetTokenHandler extends IMHandler<WFCMessage.GetTokenRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.GetTokenRequest request, Qos1PublishHandler.IMCallback callback) {\n        MemorySessionStore.Session session = m_sessionsStore.updateOrCreateUserSession(fromUser, clientID, request.getPlatform());\n        WFCMessage.User userInfo = m_messagesStore.getUserInfo(fromUser);\n        if(userInfo != null && userInfo.getType() == 1) {\n            return ErrorCode.ERROR_CODE_ROBOT_NO_TOKEN;\n        }\n        if(session.isPcClient() || session.isPadClient() || session.isTVClient()) {\n            if(m_messagesStore.isLocked(session.getUsername(), session.getClientID())) {\n                m_messagesStore.updateUserSettings(session.getUsername(), WFCMessage.ModifyUserSettingReq.newBuilder().setScope(UserSettingScope.UserSettingScopeLockPC).setKey(session.getClientID()).setValue(\"0\").build(), null);\n            }\n        }\n\n        TokenAuthenticator authenticator = new TokenAuthenticator();\n        String strToken = authenticator.generateToken(fromUser);\n        String result = strToken + \"|\" + session.getSecret() + \"|\" + session.getDbSecret();\n        byte[] data = result.getBytes();\n        ackPayload.ensureWritable(data.length).writeBytes(data);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetUserInfoHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.GetUserInfoTopic)\npublic class GetUserInfoHandler extends IMHandler<WFCMessage.PullUserRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.PullUserRequest request, Qos1PublishHandler.IMCallback callback) {\n        WFCMessage.PullUserResult.Builder resultBuilder = WFCMessage.PullUserResult.newBuilder();\n\n        ErrorCode errorCode = m_messagesStore.getUserInfo(fromUser, request.getRequestList(), resultBuilder);\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            byte[] data = resultBuilder.build().toByteArray();\n            ackPayload.ensureWritable(data.length).writeBytes(data);\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GetUserSettingHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.GetUserSettingTopic)\npublic class GetUserSettingHandler extends IMHandler<WFCMessage.Version> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.Version request, Qos1PublishHandler.IMCallback callback) {\n            WFCMessage.GetUserSettingResult.Builder builder = WFCMessage.GetUserSettingResult.newBuilder();\n            ErrorCode errorCode = m_messagesStore.getUserSettings(fromUser, request.getVersion(), builder);\n            if (errorCode == ERROR_CODE_SUCCESS) {\n                byte[] data = builder.build().toByteArray();\n                ackPayload.ensureWritable(data.length).writeBytes(data);\n            }\n            return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/GroupHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport win.liyufan.im.MessageShardingUtil;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\nabstract public class GroupHandler<T> extends IMHandler<T> {\n    protected void sendGroupNotification(String fromUser, String targetId, List<Integer> lines, WFCMessage.MessageContent content) {\n        sendGroupNotification(fromUser, targetId, lines, content, null);\n    }\n\n    protected void sendGroupNotification(String fromUser, String targetId, List<Integer> lines, WFCMessage.MessageContent content, Collection<String> toUsers) {\n        if (lines == null) {\n            lines = new ArrayList<>();\n        } else {\n            lines = new ArrayList<>(lines);\n        }\n\n        if (lines.isEmpty()) {\n            lines.add(0);\n        }\n\n        for (int line : lines) {\n            long timestamp = System.currentTimeMillis();\n            WFCMessage.Message.Builder builder = WFCMessage.Message.newBuilder().setContent(content).setServerTimestamp(timestamp);\n            builder.setConversation(builder.getConversationBuilder().setType(ProtoConstants.ConversationType.ConversationType_Group).setTarget(targetId).setLine(line));\n            builder.setFromUser(fromUser);\n            if(toUsers != null && !toUsers.isEmpty()) {\n                builder.addAllTo(toUsers);\n            }\n            try {\n                long messageId = MessageShardingUtil.generateId();\n                builder.setMessageId(messageId);\n                saveAndPublish(fromUser, null, builder.build(), ProtoConstants.RequestSourceType.Request_From_User);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    protected List<String> getMemberIdList(List<WFCMessage.GroupMember> groupMembers) {\n        List<String> out = new ArrayList<>();\n        if (groupMembers != null) {\n            for (WFCMessage.GroupMember gm : groupMembers\n                 ) {\n                out.add(gm.getMemberId());\n            }\n        }\n        return out;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/HandleFriendRequestHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport io.netty.util.internal.StringUtil;\nimport win.liyufan.im.IMTopic;\nimport win.liyufan.im.MessageShardingUtil;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_ALREADY_FRIENDS;\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.HandleFriendRequestTopic)\npublic class HandleFriendRequestHandler extends IMHandler<WFCMessage.HandleFriendRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.HandleFriendRequest request, Qos1PublishHandler.IMCallback callback) {\n            WFCMessage.Message.Builder builder = WFCMessage.Message.newBuilder();\n            builder.setFromUser(request.getTargetUid());\n            long[] heads = new long[4];\n            boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n            ErrorCode errorCode = m_messagesStore.handleFriendRequest(fromUser, request, builder, heads, isAdmin);\n\n            if (errorCode == ERROR_CODE_SUCCESS) {\n                if (!isAdmin && builder.getConversation() != null && request.getStatus() == ProtoConstants.FriendRequestStatus.RequestStatus_Accepted) {\n                    try {\n                        long messageId = MessageShardingUtil.generateId();\n                        long timestamp = System.currentTimeMillis();\n                        builder.setMessageId(messageId);\n                        builder.setServerTimestamp(timestamp);\n                        if(!StringUtil.isNullOrEmpty(builder.getContent().getSearchableContent())) {\n                            saveAndPublish(request.getTargetUid(), null, builder.build(), requestSourceType);\n                        }\n\n                        WFCMessage.MessageContent.Builder contentBuilder = WFCMessage.MessageContent.newBuilder();\n                        contentBuilder.setType(92);\n\n                        builder = WFCMessage.Message.newBuilder();\n                        builder.setFromUser(fromUser);\n                        builder.setConversation(WFCMessage.Conversation.newBuilder().setTarget(request.getTargetUid()).setLine(0).setType(ProtoConstants.ConversationType.ConversationType_Private).build());\n                        builder.setContent(contentBuilder);\n                        builder.setServerTimestamp(++timestamp);\n\n                        messageId = MessageShardingUtil.generateId();\n                        builder.setMessageId(messageId);\n                        saveAndPublish(fromUser, null, builder.build(), requestSourceType);\n                        contentBuilder.setType(93);\n                        builder.setContent(contentBuilder);\n                        messageId = MessageShardingUtil.generateId();\n                        builder.setMessageId(messageId);\n                        builder.setServerTimestamp(++timestamp);\n                        saveAndPublish(fromUser, null, builder.build(), requestSourceType);\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                    }\n                }\n                if (request.getStatus() == ProtoConstants.FriendRequestStatus.RequestStatus_Accepted || isAdmin) {\n                    publisher.publishNotification(IMTopic.NotifyFriendTopic, request.getTargetUid(), heads[0]);\n                    publisher.publishNotification(IMTopic.NotifyFriendTopic, fromUser, heads[1]);\n                }\n                if(!isAdmin) {\n                    if(heads[2] > 0) {\n                        publisher.publishNotification(IMTopic.NotifyFriendRequestTopic, request.getTargetUid(), heads[2], fromUser, null);\n                    }\n                    if(heads[3] > 0) {\n                        publisher.publishNotification(IMTopic.NotifyFriendRequestTopic, fromUser, heads[3], fromUser, null);\n                    }\n                }\n            }\n            if(errorCode == ERROR_CODE_ALREADY_FRIENDS) {\n                errorCode = ERROR_CODE_SUCCESS;\n            }\n\n            return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/Handler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n/**\n * 注解，用于自定义访问的URL路径<br>\n * 值可以是一个请求路径，如果需要指定HTTP方法，在前面加方法名用\":\"分隔既可<br>\n * @author loolly\n *\n */\n@Retention(RetentionPolicy.RUNTIME)/*保留的时间长短*/\n@Inherited/*只用于class，可被子类继承*/\npublic @interface Handler {\n\tString value();\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/IMHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.server.ThreadPoolExecutorWrapper;\nimport com.google.gson.Gson;\nimport com.google.protobuf.GeneratedMessage;\nimport com.google.protobuf.InvalidProtocolBufferException;\nimport io.moquette.server.Server;\nimport io.moquette.spi.IMessagesStore;\nimport io.moquette.spi.ISessionsStore;\nimport io.moquette.spi.impl.MessagesPublisher;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.util.internal.StringUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.GsonUtil;\nimport win.liyufan.im.RateLimiter;\nimport win.liyufan.im.Utility;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.util.*;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_OVER_FREQUENCY;\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\nimport static io.moquette.BrokerConstants.CLIENT_REQUEST_RATE_LIMIT;\nimport static win.liyufan.im.IMTopic.GetUserSettingTopic;\nimport static win.liyufan.im.IMTopic.PullMessageTopic;\n\n/**\n * 请求处理接口<br>\n * 当用户请求某个Topic，则调用相应Handler的handle方法\n *\n */\n\nabstract public class IMHandler<T> {\n    protected static final Logger LOG = LoggerFactory.getLogger(IMHandler.class);\n    protected static IMessagesStore m_messagesStore = null;\n    protected static ISessionsStore m_sessionsStore = null;\n    protected static Server mServer = null;\n    protected static MessagesPublisher publisher;\n    private static ThreadPoolExecutorWrapper m_imBusinessExecutor;\n    private static RateLimiter mLimitCounter;\n    private Method parseDataMethod;\n    private Class dataCls;\n\n    @Retention(RetentionPolicy.RUNTIME)\n    public @interface ActionMethod {\n    }\n\n    protected static String actionName;\n\n    public static MessagesPublisher getPublisher() {\n        return publisher;\n    }\n\n    public IMHandler() {\n        try {\n            if (StringUtil.isNullOrEmpty(actionName)) {\n                Class cls = getClass();\n                while (cls.getSuperclass() != null) {\n                    for (Method method : cls.getSuperclass().getDeclaredMethods()) {\n                        if (method.getAnnotation(ActionMethod.class) != null) {\n                            actionName = method.getName();\n                            break;\n                        }\n                    }\n                    if (StringUtil.isNullOrEmpty(actionName)) {\n                        cls = cls.getSuperclass();\n                    } else {\n                        break;\n                    }\n                }\n            }\n\n            Type t = getClass().getGenericSuperclass();\n            ParameterizedType p = (ParameterizedType) t ;\n            Class<T> c = (Class<T>) p.getActualTypeArguments()[0];\n            dataCls = c;\n            \n            if (dataCls.getSuperclass().equals(GeneratedMessage.class)) {\n                parseDataMethod = dataCls.getMethod(\"parseFrom\", byte[].class);\n            } else if (dataCls.isPrimitive()) {\n\n            } else {\n\n            }\n        } catch (NoSuchMethodException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n    }\n\n    private T getDataObject(byte[] bytes) throws IllegalAccessException, InvocationTargetException {\n        if (parseDataMethod != null) {\n            T object = (T) parseDataMethod.invoke(dataCls, bytes);\n            return object;\n        }\n\n        if (dataCls == String.class) {\n            String str = new String(bytes);\n            return (T)str;\n        }\n\n        if (dataCls == Byte.class) {\n            Byte b = bytes[0];\n            return (T)b;\n        }\n\n        if (dataCls == Void.class) {\n            return null;\n        }\n\n\n        //目前还没有需求传int的参数，这里先注释掉\n        //在需要使用时，需要注意大小端的问题。\n        //这里使用的示例代码是小端的，注意一定要与协议中保持一直！！！\n//        if (dataCls == Integer.class) {\n//            int i = bytes[0];\n//            for(int index = 0; index <8; index++) {\n//                i <<= 1;\n//                i += bytes[index];\n//            }\n//            Integer object = i;\n//            return (T)object;\n//         }\n\n        //json ?\n        return (T)(GsonUtil.gson.fromJson(new String(bytes), dataCls));\n    }\n\n    public static void init(IMessagesStore ms, ISessionsStore ss, MessagesPublisher p, ThreadPoolExecutorWrapper businessExecutor, Server server) {\n        m_messagesStore = ms;\n        m_sessionsStore = ss;\n        publisher = p;\n        m_imBusinessExecutor = businessExecutor;\n        mServer = server;\n        int clientRateLimit = 100;\n        try {\n            clientRateLimit = Integer.parseInt(server.getConfig().getProperty(CLIENT_REQUEST_RATE_LIMIT, \"100\"));\n        } catch (Exception e) {\n\n        }\n\n        if(clientRateLimit == 0) {\n            clientRateLimit = 100;\n        }\n\n        mLimitCounter = new RateLimiter(5, clientRateLimit);\n    }\n\n    boolean isNotLimitTopic(String topic) {\n        if (PullMessageTopic.equals(topic)\n            || GetUserSettingTopic.equals(topic)) {\n            return true;\n        }\n        return false;\n    }\n\n    public ErrorCode preAction(String clientID, String fromUser, String topic, Qos1PublishHandler.IMCallback callback, ProtoConstants.RequestSourceType requestSourceType) {\n        LOG.info(\"imHandler fromUser={}, clientId={}, topic={}\", fromUser, clientID, topic);\n        if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !isNotLimitTopic(topic) && !mLimitCounter.isGranted(clientID + fromUser + topic)) {\n            return ErrorCode.ERROR_CODE_OVER_FREQUENCY;\n        }\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n\tpublic void doHandler(String clientID, String fromUser, String topic, byte[] payloadContent, Qos1PublishHandler.IMCallback callback, ProtoConstants.RequestSourceType requestSourceType) {\n        m_imBusinessExecutor.execute(() -> {\n            Qos1PublishHandler.IMCallback callbackWrapper = new Qos1PublishHandler.IMCallback() {\n                @Override\n                public void onIMHandled(ErrorCode errorCode, ByteBuf ackPayload) {\n                    LOG.debug(\"execute handler {} with result {}\", this.getClass().getName(), errorCode);\n                    callback.onIMHandled(errorCode, ackPayload);\n                    afterAction(clientID, fromUser, topic, callback);\n                }\n            };\n\n            ErrorCode preActionCode = preAction(clientID, fromUser, topic, callbackWrapper, requestSourceType);\n\n            if (preActionCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                ByteBuf ackPayload = Unpooled.buffer(1);\n                ErrorCode errorCode = ERROR_CODE_SUCCESS;\n                ackPayload.ensureWritable(1).writeByte(errorCode.getCode());\n\n                try {\n                    LOG.debug(\"execute handler for topic {}\", topic);\n                    errorCode = action(ackPayload, clientID, fromUser, requestSourceType, getDataObject(payloadContent), callbackWrapper);\n                } catch (IllegalAccessException e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e);\n                    errorCode = ErrorCode.ERROR_CODE_INVALID_DATA;\n                } catch (InvocationTargetException e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e);\n                    errorCode = ErrorCode.ERROR_CODE_INVALID_DATA;\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e);\n                    if (e instanceof InvalidProtocolBufferException) {\n                        errorCode = ErrorCode.ERROR_CODE_INVALID_DATA;\n                    } else {\n                        errorCode = ErrorCode.ERROR_CODE_SERVER_ERROR;\n                    }\n                }\n                if(errorCode != ErrorCode.INVALID_ASYNC_HANDLING) {\n                    response(ackPayload, errorCode, callback);\n                }\n            } else {\n                LOG.error(\"Handler {} preAction failure\", this.getClass().getName());\n                ByteBuf ackPayload = Unpooled.buffer(1);\n                ackPayload.ensureWritable(1).writeByte(preActionCode.getCode());\n                response(ackPayload, preActionCode, callback);\n            }\n        });\n    }\n\n    private void response(ByteBuf ackPayload, ErrorCode errorCode, Qos1PublishHandler.IMCallback callback) {\n        ackPayload.setByte(0, errorCode.getCode());\n        try {\n            callback.onIMHandled(errorCode, ackPayload);\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n    }\n\n\n    @ActionMethod\n    abstract public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, T request, Qos1PublishHandler.IMCallback callback)   ;\n\n    public void afterAction(String clientID, String fromUser, String topic, Qos1PublishHandler.IMCallback callback) {\n\n    }\n    protected long publish(String username, String clientID, WFCMessage.Message message, ProtoConstants.RequestSourceType requestSourceType) {\n        Set<String> notifyReceivers = new LinkedHashSet<>();\n\n        WFCMessage.Message.Builder messageBuilder = message.toBuilder();\n        int pullType = m_messagesStore.getNotifyReceivers(username, messageBuilder, notifyReceivers, requestSourceType);\n        mServer.getImBusinessScheduler().execute(() -> this.publisher.publish2Receivers(messageBuilder.build(), notifyReceivers, clientID, pullType));\n        return notifyReceivers.size();\n    }\n\n    protected long saveAndPublish(String username, String clientID, WFCMessage.Message message, ProtoConstants.RequestSourceType requestSourceType) {\n        Set<String> notifyReceivers = new LinkedHashSet<>();\n\n        message = m_messagesStore.storeMessage(username, clientID, message);\n        WFCMessage.Message.Builder messageBuilder = message.toBuilder();\n        int pullType = m_messagesStore.getNotifyReceivers(username, messageBuilder, notifyReceivers, requestSourceType);\n        mServer.getImBusinessScheduler().execute(() -> this.publisher.publish2Receivers(messageBuilder.build(), notifyReceivers, clientID, pullType));\n        return notifyReceivers.size();\n    }\n\n    protected long saveAndBroadcast(String username, String clientID, WFCMessage.Message message) {\n        Set<String> notifyReceivers = m_messagesStore.getAllEnds();\n        WFCMessage.Message updatedMessage = m_messagesStore.storeMessage(username, clientID, message);\n        mServer.getImBusinessScheduler().execute(() -> publisher.publish2Receivers(updatedMessage, notifyReceivers, clientID, ProtoConstants.PullType.Pull_Normal));\n        return notifyReceivers.size();\n    }\n\n    protected long saveAndMulticast(String username, String clientID, WFCMessage.Message message, Collection<String> targets) {\n        Set<String> notifyReceivers = new HashSet<>();\n        notifyReceivers.addAll(targets);\n        WFCMessage.Message updatedMessage = m_messagesStore.storeMessage(username, clientID, message);\n        mServer.getImBusinessScheduler().execute(() -> publisher.publish2Receivers(updatedMessage, notifyReceivers, clientID, ProtoConstants.PullType.Pull_Normal));\n        return notifyReceivers.size();\n    }\n    protected long publishRecallMultiCastMsg(long messageUid, List<String> receivers) {\n        WFCMessage.Message updatedMessage = m_messagesStore.getMessage(messageUid);\n\n        Set<String> notifyReceivers = new HashSet<>(receivers);\n        LOG.info(\"Multicast recall receiver count: {}\", notifyReceivers.size());\n        mServer.getImBusinessScheduler().execute(() -> publisher.publish2Receivers(updatedMessage, notifyReceivers, null, ProtoConstants.PullType.Pull_Normal));\n\n        return notifyReceivers.size();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/JoinChatroomHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n\n@Handler(IMTopic.JoinChatroomTopic)\npublic class JoinChatroomHandler extends IMHandler<WFCMessage.IDBuf> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.IDBuf request, Qos1PublishHandler.IMCallback callback) {\n        return m_messagesStore.handleJoinChatroom(fromUser, clientID, request.getId());\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/KickoffGroupMember.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.pojos.GroupNotificationBinaryContent;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\n\nimport java.util.Set;\n\nimport static win.liyufan.im.IMTopic.KickoffGroupMemberTopic;\n\n@Handler(value = KickoffGroupMemberTopic)\npublic class KickoffGroupMember extends GroupHandler<WFCMessage.RemoveGroupMemberRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.RemoveGroupMemberRequest request, Qos1PublishHandler.IMCallback callback) {\n        ErrorCode errorCode;\n        WFCMessage.GroupInfo groupInfo = m_messagesStore.getGroupInfo(request.getGroupId());\n        if (groupInfo == null) {\n            errorCode = ErrorCode.ERROR_CODE_NOT_EXIST;\n        } else {\n            boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n            if (!isAdmin && groupInfo.getType() == ProtoConstants.GroupType.GroupType_Organization) {\n                return ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n\n            boolean isAllow = isAdmin;\n            if (!isAllow) {\n                if (groupInfo.getOwner() != null) {\n                    if (request.getRemovedMemberList().contains(groupInfo.getOwner())) {\n                        return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                    }\n                }\n\n                if (groupInfo.getOwner() != null && groupInfo.getOwner().equals(fromUser)) {\n                    isAllow = true;\n                }\n            }\n\n            if (!isAllow) {\n                WFCMessage.GroupMember gm = m_messagesStore.getGroupMember(request.getGroupId(), fromUser);\n                if (gm != null && gm.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Manager) {\n                    isAllow = true;\n                }\n            }\n            if (!isAllow && (groupInfo.getType() == ProtoConstants.GroupType.GroupType_Normal || groupInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted)) {\n                errorCode = ErrorCode.ERROR_CODE_NOT_RIGHT;\n            } else {\n                if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !m_messagesStore.isAllowClientCustomGroupNotification()) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n                if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot && !m_messagesStore.isAllowRobotCustomGroupNotification()) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n\n                if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {\n                    int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();\n                    if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Kickoff_Group_Member) > 0) {\n                        return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                    }\n                }\n\n                //send notify message first, then kickoff the member\n                if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {\n                    sendGroupNotification(fromUser, groupInfo.getTargetId(), request.getToLineList(), request.getNotifyContent());\n                } else {\n                    WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, request.getRemovedMemberList()).getKickokfMemberGroupNotifyContent();\n                    sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);\n                }\n\n                if((m_messagesStore.getVisibleQuitKickoffNotification() & 0x02) > 0) {\n                    Set<String> toUsers = m_messagesStore.getGroupManagers(request.getGroupId(), true);\n                    toUsers.addAll(request.getRemovedMemberList());\n                    WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, request.getRemovedMemberList()).getKickokfMemberVisibleGroupNotifyContent();\n                    sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content, toUsers);\n                }\n                errorCode = m_messagesStore.kickoffGroupMembers(fromUser, isAdmin, request.getGroupId(), request.getRemovedMemberList());\n            }\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/KickoffPCClientHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.GroupNotificationBinaryContent;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\n\nimport static win.liyufan.im.IMTopic.KickoffGroupMemberTopic;\nimport static win.liyufan.im.IMTopic.KickoffPCClientTopic;\n\n@Handler(value = KickoffPCClientTopic)\npublic class KickoffPCClientHandler extends GroupHandler<WFCMessage.IDBuf> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.IDBuf request, Qos1PublishHandler.IMCallback callback) {\n        String pcClientId = request.getId();\n        if (StringUtil.isNullOrEmpty(pcClientId)) {\n            return ErrorCode.INVALID_PARAMETER;\n        }\n\n        return m_sessionsStore.kickoffPCClient(fromUser, pcClientId);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/LoadRemoteMessagesHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Handler(value = IMTopic.LoadRemoteMessagesTopic)\npublic class LoadRemoteMessagesHandler extends IMHandler<WFCMessage.LoadRemoteMessages> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.LoadRemoteMessages request, Qos1PublishHandler.IMCallback callback) {\n        ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n\n        long beforeUid = request.getBeforeUid();\n        if (beforeUid == 0) {\n            beforeUid = Long.MAX_VALUE;\n        }\n\n        if (request.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Group) {\n            if (!m_messagesStore.isMemberInGroup(fromUser, request.getConversation().getTarget())) {\n                return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n            }\n        }\n\n        if (request.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Channel) {\n            if (!m_messagesStore.canSendMessageInChannel(fromUser, request.getConversation().getTarget())) {\n                return ErrorCode.ERROR_CODE_NOT_IN_CHANNEL;\n            }\n        }\n\n        WFCMessage.PullMessageResult result = m_messagesStore.loadRemoteMessages(fromUser, request.getConversation(), beforeUid, request.getCount(), request.getContentTypeList());\n        byte[] data = result.toByteArray();\n        LOG.info(\"User {} load message with count({}), payload size({})\", fromUser, result.getMessageCount(), data.length);\n        ackPayload.ensureWritable(data.length).writeBytes(data);\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/ModifyChannelInfoHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\n\nimport static win.liyufan.im.IMTopic.ModifyChannelInfoTopic;\n\n@Handler(value = ModifyChannelInfoTopic)\npublic class ModifyChannelInfoHandler extends GroupHandler<WFCMessage.ModifyChannelInfo> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.ModifyChannelInfo request, Qos1PublishHandler.IMCallback callback) {\n        ErrorCode errorCode= m_messagesStore.modifyChannelInfo(fromUser, request.getChannelId(), request.getType(), request.getValue());\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/ModifyGroupAliasHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.pojos.GroupNotificationBinaryContent;\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.Set;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.ModifyGroupAliasTopic)\npublic class ModifyGroupAliasHandler extends GroupHandler<WFCMessage.ModifyGroupMemberAlias> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.ModifyGroupMemberAlias request, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !m_messagesStore.isAllowClientCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot && !m_messagesStore.isAllowRobotCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if (!isAdmin && !StringUtil.isNullOrEmpty(request.getAlias())) {\n            if(!m_messagesStore.isSensitiveOnlyMessage()) {\n                Set<String> matched = m_messagesStore.handleSensitiveWord(request.getAlias());\n                if (matched != null && !matched.isEmpty()) {\n                    return ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;\n                }\n            }\n\n            if(!m_messagesStore.isAllowName(request.getAlias())) {\n                return ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n        }\n\n        ErrorCode errorCode = m_messagesStore.modifyGroupMemberAlias(fromUser, request.getGroupId(), request.getAlias(), null, isAdmin);\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            if (request.hasNotifyContent()&& request.getNotifyContent().getType() > 0) {\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());\n            } else {\n                WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getAlias(), \"\").getModifyGroupMemberAliasNotifyContent();\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);\n            }\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/ModifyGroupInfoHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.pojos.GroupNotificationBinaryContent;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\nimport static cn.wildfirechat.proto.ProtoConstants.ModifyGroupInfoType.*;\nimport static win.liyufan.im.IMTopic.ModifyGroupInfoTopic;\n\n@Handler(value = ModifyGroupInfoTopic)\npublic class ModifyGroupInfoHandler extends GroupHandler<WFCMessage.ModifyGroupInfoRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.ModifyGroupInfoRequest request, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !m_messagesStore.isAllowClientCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot && !m_messagesStore.isAllowRobotCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {\n            int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();\n            if(request.getType() == Modify_Group_Mute) {\n                if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Mute_Group) > 0) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n            } else {\n                if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Modify_Group_Info) > 0) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n            }\n        }\n\n        ErrorCode errorCode= m_messagesStore.modifyGroupInfo(fromUser, request.getGroupId(), request.getType(), request.getValue(), isAdmin);\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());\n            } else {\n                WFCMessage.MessageContent content = null;\n                if (request.getType() == Modify_Group_Name) {\n                    content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getValue(), \"\").getChangeGroupNameNotifyContent();\n                } else if(request.getType() == Modify_Group_Portrait) {\n                    content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getValue(), \"\").getChangeGroupPortraitNotifyContent();\n                } else if(request.getType() == Modify_Group_Mute) {\n                    content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getValue(), \"\").getChangeGroupMuteNotifyContent();\n                } else if(request.getType() == Modify_Group_JoinType) {\n                    content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getValue(), \"\").getChangeGroupJointypeNotifyContent();\n                } else if(request.getType() == Modify_Group_PrivateChat) {\n                    content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getValue(), \"\").getChangeGroupPrivatechatNotifyContent();\n                } else if(request.getType() == Modify_Group_Searchable) {\n                    content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getValue(), \"\").getChangeGroupSearchableNotifyContent();\n                } else if(request.getType() == Modify_Group_Extra) {\n                    content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getValue(), \"\").getChangeGroupExtraNotifyContent();\n                }\n\n                if (content != null) {\n                    sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);\n                }\n            }\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/ModifyGroupMemberAliasHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.GroupNotificationBinaryContent;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.Set;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.ModifyGroupMemberAliasTopic)\npublic class ModifyGroupMemberAliasHandler extends GroupHandler<WFCMessage.ModifyGroupMemberAlias> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.ModifyGroupMemberAlias request, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !m_messagesStore.isAllowClientCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot && !m_messagesStore.isAllowRobotCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n        if (!isAdmin && !StringUtil.isNullOrEmpty(request.getAlias())) {\n            if(!m_messagesStore.isSensitiveOnlyMessage()) {\n                Set<String> matched = m_messagesStore.handleSensitiveWord(request.getAlias());\n                if (matched != null && !matched.isEmpty()) {\n                    return ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;\n                }\n            }\n\n            if(!m_messagesStore.isAllowName(request.getAlias())) {\n                return ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n        }\n\n        ErrorCode errorCode = m_messagesStore.modifyGroupMemberAlias(fromUser, request.getGroupId(), request.getAlias(), request.getMemberId(), isAdmin);\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            if (request.hasNotifyContent()&& request.getNotifyContent().getType() > 0) {\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());\n            } else {\n                WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getAlias(), request.getMemberId()).getModifyGroupMemberAliasNotifyContent();\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);\n            }\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/ModifyGroupMemberExtraHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.GroupNotificationBinaryContent;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.ModifyGroupMemberExtraTopic)\npublic class ModifyGroupMemberExtraHandler extends GroupHandler<WFCMessage.ModifyGroupMemberExtra> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.ModifyGroupMemberExtra request, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !m_messagesStore.isAllowClientCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot && !m_messagesStore.isAllowRobotCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        ErrorCode errorCode = m_messagesStore.modifyGroupMemberExtra(fromUser, request.getGroupId(), request.getExtra(), request.getMemberId(), isAdmin);\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            if (request.hasNotifyContent()&& request.getNotifyContent().getType() > 0) {\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());\n            } else {\n                WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getExtra(), request.getMemberId()).getModifyGroupMemberExtraNotifyContent();\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);\n            }\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/ModifyMyInfoHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\nimport win.liyufan.im.Utility;\n\n@Handler(IMTopic.ModifyMyInfoTopic)\npublic class ModifyMyInfoHandler extends IMHandler<WFCMessage.ModifyMyInfoRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.ModifyMyInfoRequest request, Qos1PublishHandler.IMCallback callback) {\n        try {\n            return m_messagesStore.modifyUserInfo(fromUser, request);\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            return ErrorCode.ERROR_CODE_SERVER_ERROR;\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/MultiCastMessageHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.BrokerConstants;\nimport io.moquette.server.Server;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\nimport win.liyufan.im.MessageShardingUtil;\n\nimport java.util.Set;\n\nimport static cn.wildfirechat.proto.ProtoConstants.ContentType.Text;\nimport static cn.wildfirechat.proto.ProtoConstants.ConversationType.ConversationType_Private;\n\n@Handler(value = IMTopic.MultiCastMessageTopic)\npublic class MultiCastMessageHandler extends IMHandler<WFCMessage.MultiCastMessage> {\n\n\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.MultiCastMessage multiCastMessage, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n        if (!isAdmin) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        long timestamp = System.currentTimeMillis();\n        long messageId = 0;\n        try {\n            messageId = MessageShardingUtil.generateId();\n        } catch (Exception e) {\n            e.printStackTrace();\n            return ErrorCode.ERROR_CODE_SERVER_ERROR;\n        }\n        WFCMessage.Message message = WFCMessage.Message.newBuilder()\n            .setContent(multiCastMessage.getContent())\n            .setConversation(WFCMessage.Conversation.newBuilder().setTarget(fromUser).setType(ConversationType_Private).setLine(multiCastMessage.getLine()).build())\n            .setFromUser(fromUser)\n            .setMessageId(messageId)\n            .setServerTimestamp(timestamp)\n            .build();\n\n        saveAndMulticast(fromUser, clientID, message, multiCastMessage.getToList());\n\n        ackPayload = ackPayload.capacity(20);\n        ackPayload.writeLong(messageId);\n        ackPayload.writeLong(timestamp);\n\n        return errorCode;\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/PullMessageHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Handler(value = IMTopic.PullMessageTopic)\npublic class PullMessageHandler extends IMHandler<WFCMessage.PullMessageRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.PullMessageRequest request, Qos1PublishHandler.IMCallback callback) {\n        ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n\n        if (request.getType() == ProtoConstants.PullType.Pull_ChatRoom && !m_messagesStore.checkUserClientInChatroom(fromUser, clientID, null)) {\n            errorCode = ErrorCode.ERROR_CODE_NOT_IN_CHATROOM;\n        } else {\n            WFCMessage.PullMessageResult result = m_messagesStore.fetchMessage(fromUser, clientID, request.getId(), request.getType());\n            byte[] data = result.toByteArray();\n            LOG.info(\"User {} pull message with count({}), payload size({})\", fromUser, result.getMessageCount(), data.length);\n            ackPayload.ensureWritable(data.length).writeBytes(data);\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/PutUserSettingHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Handler(IMTopic.PutUserSettingTopic)\npublic class PutUserSettingHandler extends IMHandler<WFCMessage.ModifyUserSettingReq> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.ModifyUserSettingReq request, Qos1PublishHandler.IMCallback callback) {\n            m_messagesStore.updateUserSettings(fromUser, request, clientID);\n            return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/QuitChatroomHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Handler(IMTopic.QuitChatroomTopic)\npublic class QuitChatroomHandler extends IMHandler<WFCMessage.IDBuf> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.IDBuf request, Qos1PublishHandler.IMCallback callback) {\n        m_messagesStore.handleQuitChatroom(fromUser, clientID, request.getId());\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/QuitGroupHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.pojos.GroupNotificationBinaryContent;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\n\nimport java.util.Set;\n\nimport static win.liyufan.im.IMTopic.QuitGroupTopic;\n\n@Handler(value = QuitGroupTopic)\npublic class QuitGroupHandler extends GroupHandler<WFCMessage.QuitGroupRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.QuitGroupRequest request, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !m_messagesStore.isAllowClientCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot && !m_messagesStore.isAllowRobotCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {\n            int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();\n            if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Quit_Group) > 0) {\n                return ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n        }\n\n        ErrorCode errorCode = m_messagesStore.quitGroup(fromUser, request.getGroupId(), isAdmin);\n        if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());\n            } else {\n                WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getKeepMsg()>0?\"1\":\"0\", \"\").getQuitGroupNotifyContent();\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);\n            }\n\n            if((m_messagesStore.getVisibleQuitKickoffNotification() & 0x01) > 0) {\n                Set<String> toUsers = m_messagesStore.getGroupManagers(request.getGroupId(), true);\n                WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getKeepMsg()>0?\"1\":\"0\", \"\").getQuitVisibleGroupNotifyContent();\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content, toUsers);\n            }\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/RecallMessageHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.LinkedHashSet;\nimport java.util.Set;\n\n@Handler(value = IMTopic.RecallMessageTopic)\npublic class RecallMessageHandler extends IMHandler<WFCMessage.INT64Buf> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.INT64Buf int64Buf, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        ErrorCode errorCode = m_messagesStore.recallMessage(int64Buf.getId(), fromUser, clientID, isAdmin, ackPayload);\n\n        if(errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n            return errorCode;\n        }\n\n        WFCMessage.Message message = m_messagesStore.getMessage(int64Buf.getId());\n        if (message == null) {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n        publish(message.getFromUser(), clientID, message, requestSourceType);\n\n        return errorCode;\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/RecallMultiCastMessageHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\n\n@Handler(value = IMTopic.RecallMultiCastMessageTopic)\npublic class RecallMultiCastMessageHandler extends IMHandler<WFCMessage.RecallMultiCastMessageRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.RecallMultiCastMessageRequest request, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        if (!isAdmin) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        ErrorCode errorCode = m_messagesStore.recallCastMessage(request.getMessageId(), fromUser);\n\n        if(errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n            return errorCode;\n        }\n\n        publishRecallMultiCastMsg(request.getMessageId(), request.getReceiverList());\n\n        return errorCode;\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/ReplyMessageHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.BrokerConstants;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport win.liyufan.im.*;\n\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_NOT_IN_GROUP;\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(value = IMTopic.RobotReplyMessageTopic)\npublic class ReplyMessageHandler extends IMHandler<WFCMessage.Message> {\n    private int mSensitiveType = 0;  //命中敏感词时，0 失败，1 吞掉， 2 敏感词替换成*。\n    private String mForwardUrl = null;\n    private String mSensitiveMessageForwardUrl = null;\n    private Set<Integer> mForwardMessageTypes = new HashSet<>();\n    private Set<Integer> mForwardExcludeMessageTypes = new HashSet<>();\n    private String mMentionForwardUrl = null;\n    private int mBlacklistStrategy = 0; //黑名单中时，0失败，1吞掉。\n    private boolean mBlacklistAllowSend2Black = true;\n    private boolean mNoForwardAdminMessage = false;\n    private boolean mAllowSend2ForbiddenUser = false;\n\n    private String mRemoteSensitiveServerUrl = null;\n    private Set<Integer> mRemoteSensitiveMessageTypes;\n    private boolean mWaitRemoteSensitiveServerResponse = false;\n\n    public ReplyMessageHandler() {\n        super();\n\n        mForwardUrl = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_Url);\n        if (!StringUtil.isNullOrEmpty(mForwardUrl)) {\n            String forwardTypes = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_Types);\n            parseTypes(mForwardMessageTypes, forwardTypes);\n            String excludeTypes = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_Exclude_Types);\n            parseTypes(mForwardExcludeMessageTypes, excludeTypes);\n        }\n        mSensitiveMessageForwardUrl = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Sensitive_Forward_Url);\n        mMentionForwardUrl = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_MentionMsg_Forward_Url);\n\n        try {\n            mSensitiveType = Integer.parseInt(mServer.getConfig().getProperty(BrokerConstants.SENSITIVE_Filter_Type));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        try {\n            mBlacklistStrategy = Integer.parseInt(mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Blacklist_Strategy));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        try {\n            mBlacklistAllowSend2Black = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Blacklist_Allow_Send, \"true\"));\n        } catch (Exception e) {\n        }\n\n        try {\n            mRemoteSensitiveServerUrl = mServer.getConfig().getProperty(BrokerConstants.SENSITIVE_Remote_Server_URL);\n            if(!StringUtil.isNullOrEmpty(mRemoteSensitiveServerUrl)) {\n                mWaitRemoteSensitiveServerResponse = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.SENSITIVE_Remote_Fail_When_Matched, \"false\"));\n                String types = mServer.getConfig().getProperty(BrokerConstants.SENSITIVE_Remote_Message_Type, \"\");\n                mRemoteSensitiveMessageTypes = new HashSet<>();\n                if(!StringUtil.isNullOrEmpty(types)) {\n                    String[] ts = types.split(\",\");\n                    for (String t:ts) {\n                        mRemoteSensitiveMessageTypes.add(Integer.parseInt(t.trim()));\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        try {\n            mNoForwardAdminMessage = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.MESSAGE_NO_Forward_Admin_Message, \"false\"));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        try {\n            mAllowSend2ForbiddenUser = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.MESSAGES_ALLOW_SEND_TO_FORBIDDEN_USER, \"false\"));\n        } catch (Exception e) {}\n    }\n\n    private void parseTypes(Collection<Integer> collection, String types) {\n        try {\n            if (!StringUtil.isNullOrEmpty(types)) {\n                String[] tss = types.split(\",\");\n                for (String ts:tss) {\n                    if(ts.contains(\"-\")) {\n                        String[] ss = ts.split(\"-\");\n                        if(ss.length == 2) {\n                            int begin = Integer.parseInt(ss[0]);\n                            int end = Integer.parseInt(ss[1]);\n                            for (int i = begin; i <= end ; i++) {\n                                collection.add(i);\n                            }\n                        }\n                    } else {\n                        collection.add(Integer.parseInt(ts.trim()));\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.Message message, Qos1PublishHandler.IMCallback callback) {\n        if(requestSourceType != ProtoConstants.RequestSourceType.Request_From_Robot) {\n            return ErrorCode.ERROR_CODE_NOT_IMPLEMENT;\n        }\n\n        ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n\n        if (message != null) {\n            if(message.getContent().getContent().length() +\n                message.getContent().getSearchableContent().length() +\n                message.getContent().getData().size() +\n                message.getContent().getExtra().length() +\n                message.getContent().getPushContent().length() +\n                message.getContent().getPushData().length() > 64 * 1024) {\n                return ErrorCode.ERROR_CODE_MESSAGE_TOO_LARGE;\n            }\n\n            boolean ignoreMsg = false;\n\n                // 不能在端上直接发送撤回和群通知\n                if (message.getContent().getType() == 80 || message.getContent().getType() == 81 || (message.getContent().getType() >= 100 && message.getContent().getType() < 200)) {\n                    return ErrorCode.INVALID_PARAMETER;\n                }\n\n                if(m_messagesStore.getClientForbiddenSendTypes().contains(message.getContent().getType())) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n\n                int userStatus = m_messagesStore.getUserStatus(fromUser);\n                if (userStatus == ProtoConstants.UserStatus.Muted || userStatus == ProtoConstants.UserStatus.Forbidden) {\n                    if(!m_messagesStore.getGlobalMuteExceptionTypes().contains(message.getContent().getType())) {\n                        return ErrorCode.ERROR_CODE_FORBIDDEN_SEND_MSG;\n                    }\n                }\n\n                if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Private) {\n                    if(!m_messagesStore.getBlackListExceptionTypes().contains(message.getContent().getType())) {\n                        errorCode = m_messagesStore.isAllowUserMessage(message.getConversation().getTarget(), fromUser, message.getConversation().getLine());\n                        if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                            if (errorCode == ErrorCode.ERROR_CODE_IN_BLACK_LIST && mBlacklistStrategy != ProtoConstants.BlacklistStrategy.Message_Reject) {\n                                ignoreMsg = true;\n                                errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n                            } else {\n                                return errorCode;\n                            }\n                        }\n\n                        if(!mBlacklistAllowSend2Black) {\n                            errorCode = m_messagesStore.isBlacked(fromUser, message.getConversation().getTarget());\n                            if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                                return errorCode;\n                            }\n                        }\n                    }\n\n                    if (!mAllowSend2ForbiddenUser) {\n                        userStatus = m_messagesStore.getUserStatus(message.getConversation().getTarget());\n                        if (userStatus == ProtoConstants.UserStatus.Forbidden) {\n                            return ErrorCode.ERROR_CODE_USER_FORBIDDEN;\n                        }\n                    }\n                }\n\n                if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Group ) {\n                    if(!m_messagesStore.getGroupMuteExceptionTypes().contains(message.getContent().getType())) {\n                        errorCode = m_messagesStore.canSendMessageInGroup(fromUser, message.getConversation().getTarget());\n                        if(errorCode == ERROR_CODE_NOT_IN_GROUP) {\n                            errorCode = ERROR_CODE_SUCCESS;\n                        }\n                        if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                            return errorCode;\n                        }\n                    }\n                } else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_ChatRoom) {\n                    if(!m_messagesStore.getGroupMuteExceptionTypes().contains(message.getContent().getType())) {\n                        if (!m_messagesStore.checkUserClientInChatroom(fromUser, clientID, message.getConversation().getTarget())) {\n                            return ErrorCode.ERROR_CODE_NOT_IN_CHATROOM;\n                        }\n                    }\n                } else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Channel) {\n                    if(!m_messagesStore.getGroupMuteExceptionTypes().contains(message.getContent().getType())) {\n                        if (!m_messagesStore.canSendMessageInChannel(fromUser, message.getConversation().getTarget())) {\n                            return ErrorCode.ERROR_CODE_NOT_IN_CHANNEL;\n                        }\n                    }\n                }\n\n            if(message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Private) {\n                long beforeMessageId = message.getMessageId();\n                WFCMessage.Message replyMsg = m_messagesStore.getMessage(beforeMessageId);\n                message = message.toBuilder().setConversation(message.getConversation().toBuilder().setTarget(replyMsg.getFromUser() + \"|\" + replyMsg.getConversation().getTarget())).build();\n            }\n\n            long timestamp = System.currentTimeMillis();\n            final long messageId;\n            try {\n                messageId = MessageShardingUtil.generateId();\n            } catch (Exception e) {\n                e.printStackTrace();\n                return ErrorCode.ERROR_CODE_SERVER_ERROR;\n            }\n            message = message.toBuilder().setFromUser(fromUser).setMessageId(messageId).setServerTimestamp(timestamp).build();\n\n\n            if (!StringUtil.isNullOrEmpty(mForwardUrl) && (mForwardMessageTypes.isEmpty() || mForwardMessageTypes.contains(message.getContent().getType()))  && !mForwardExcludeMessageTypes.contains(message.getContent().getType())) {\n                publisher.forwardMessage(message, mForwardUrl, clientID);\n            }\n\n            if(!StringUtil.isNullOrEmpty(mMentionForwardUrl) && message.hasContent() && message.getContent().getMentionedType() != 0) {\n                publisher.forwardMessage(message, mMentionForwardUrl, clientID);\n            }\n\n\n                if(StringUtil.isNullOrEmpty(mRemoteSensitiveServerUrl)) {\n                    Set<String> matched = m_messagesStore.handleSensitiveWord(message.getContent().getSearchableContent());\n                    if (matched != null && !matched.isEmpty()) {\n                        m_messagesStore.storeSensitiveMessage(message);\n                        if (!StringUtil.isNullOrEmpty(mSensitiveMessageForwardUrl)) {\n                            publisher.forwardMessage(message, mSensitiveMessageForwardUrl, clientID);\n                        }\n                        if (mSensitiveType == 0) {\n                            errorCode = ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;\n                        } else if (mSensitiveType == 1) {\n                            ignoreMsg = true;\n                        } else if (mSensitiveType == 2) {\n                            String text = message.getContent().getSearchableContent();\n                            for (String word : matched) {\n                                text = text.replace(word, \"***\");\n                            }\n                            message = message.toBuilder().setContent(message.getContent().toBuilder().setSearchableContent(text).build()).build();\n                        }\n                    }\n                } else {\n                    if(mRemoteSensitiveMessageTypes.contains(message.getContent().getType())) {\n                        final WFCMessage.Message finalMsg = message;\n                        publisher.forwardMessageWithCallback(message, clientID, mRemoteSensitiveServerUrl, new HttpUtils.HttpCallback() {\n                            @Override\n                            public void onSuccess(String content) {\n                                if(StringUtil.isNullOrEmpty(content)) {\n                                    saveAndPublish(fromUser, clientID, finalMsg, requestSourceType);\n                                } else {\n                                    MessagePayload payload = GsonUtil.gson.fromJson(content, MessagePayload.class);\n                                    if (payload != null && payload.getType() > 0) {\n                                        WFCMessage.Message newMsg = finalMsg.toBuilder().setContent(payload.toProtoMessageContent()).build();\n                                        saveAndPublish(fromUser, clientID, newMsg, requestSourceType);\n                                    } else {\n                                        LOG.error(\"Response content {} from censor is invalid payload, ignore response and send original message\", content);\n                                        saveAndPublish(fromUser, clientID, finalMsg, requestSourceType);\n                                    }\n                                }\n                                if(mWaitRemoteSensitiveServerResponse) {\n                                    ByteBuf ackPayload = Unpooled.buffer(21);\n                                    ErrorCode errorCode = ERROR_CODE_SUCCESS;\n                                    ackPayload.writeByte(errorCode.getCode());\n                                    ackPayload.writeLong(messageId);\n                                    ackPayload.writeLong(timestamp);\n                                    callback.onIMHandled(ErrorCode.ERROR_CODE_SUCCESS, ackPayload);\n                                }\n                            }\n\n                            @Override\n                            public void onFailure(int statusCode, String errorMessage) {\n                                ByteBuf ackPayload = null;\n                                ErrorCode errorCode = ERROR_CODE_SUCCESS;\n                                if(statusCode == 403) {\n                                    if(mWaitRemoteSensitiveServerResponse) {\n                                        errorCode = ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;\n                                        ackPayload = Unpooled.buffer(1);\n                                        ackPayload.writeByte(errorCode.getCode());\n                                    }\n                                } else {\n                                    LOG.warn(\"Failed to censor message with status {}, errorMessage {}. Send the original message\", statusCode, errorMessage);\n                                    saveAndPublish(fromUser, clientID, finalMsg, requestSourceType);\n\n                                    if(mWaitRemoteSensitiveServerResponse) {\n                                        errorCode = ERROR_CODE_SUCCESS;\n                                        ackPayload = Unpooled.buffer(21);\n                                        ackPayload.writeByte(errorCode.getCode());\n                                        ackPayload.writeLong(messageId);\n                                        ackPayload.writeLong(timestamp);\n                                    }\n                                }\n\n                                if(mWaitRemoteSensitiveServerResponse) {\n                                    callback.onIMHandled(errorCode, ackPayload);\n                                }\n                            }\n                        });\n\n                        if(mWaitRemoteSensitiveServerResponse) {\n                            ackPayload.clear();\n                            return ErrorCode.INVALID_ASYNC_HANDLING;\n                        } else {\n                            ackPayload = ackPayload.capacity(20);\n                            ackPayload.writeLong(messageId);\n                            ackPayload.writeLong(timestamp);\n                            return ErrorCode.ERROR_CODE_SUCCESS;\n                        }\n                    }\n                }\n\n            if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                if(!ignoreMsg) {\n                    saveAndPublish(fromUser, clientID, message, requestSourceType);\n                }\n                ackPayload = ackPayload.capacity(20);\n                ackPayload.writeLong(messageId);\n                ackPayload.writeLong(timestamp);\n            }\n        } else {\n            errorCode = ErrorCode.ERROR_CODE_INVALID_MESSAGE;\n        }\n        return errorCode;\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/RouteHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.core.Member;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.moquette.spi.ClientSession;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Handler(IMTopic.RouteTopic)\npublic class RouteHandler extends IMHandler<WFCMessage.RouteRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.RouteRequest request, Qos1PublishHandler.IMCallback callback) {\n        MemorySessionStore.Session session = m_sessionsStore.sessionForClientAndUser(fromUser, clientID);\n        if (session == null) {\n            ErrorCode errorCode = m_sessionsStore.loadActiveSession(fromUser, clientID);\n            if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                return errorCode;\n            }\n            session = m_sessionsStore.sessionForClientAndUser(fromUser, clientID);\n        }\n\n        if (session == null || session.getDeleted() > 0) {\n            if(session == null) {\n                LOG.error(\"Session for <{}, {}> not exist\", fromUser, clientID);\n            } else {\n                LOG.error(\"Session for <{}, {}> deleted\", fromUser, clientID);\n            }\n            return ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH;\n        }\n\n        if(request.getPlatform() != session.getPlatform() && m_messagesStore.existSignatures()) {\n            LOG.error(\"Session <{}, {}> platform is {} mismatch the request {}\", session.getUsername(), session.getClientID(), session.getPlatform(), request.getPlatform());\n            return ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH;\n        }\n\n        String serverIp = mServer.getServerIp();\n        String longPort = mServer.getLongPort();\n        String shortPort = mServer.getShortPort();\n\n        ClientSession clientSession = m_sessionsStore.sessionForClient(clientID);\n        boolean isSessionAlreadyStored = clientSession != null;\n        if (!isSessionAlreadyStored) {\n            m_sessionsStore.loadActiveSession(fromUser, clientID);\n        } else {\n            m_sessionsStore.updateExistSession(fromUser, clientID, request, true);\n        }\n\n        WFCMessage.RouteResponse response = WFCMessage.RouteResponse.newBuilder().setHost(serverIp).setLongPort(Integer.parseInt(longPort)).setShortPort(Integer.parseInt(shortPort)).build();\n\n        byte[] data = response.toByteArray();\n        ackPayload.ensureWritable(data.length).writeBytes(data);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/SendMessageHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.pojos.OutputClient;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.BrokerConstants;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport io.netty.buffer.Unpooled;\nimport win.liyufan.im.*;\n\nimport java.util.Collection;\nimport java.util.HashSet;\nimport java.util.Set;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(value = IMTopic.SendMessageTopic)\npublic class SendMessageHandler extends IMHandler<WFCMessage.Message> {\n    private int mSensitiveType = 0;  //命中敏感词时，0 失败，1 吞掉， 2 敏感词替换成*。\n    private String mForwardUrl = null;\n    private String mSensitiveMessageForwardUrl = null;\n    private Set<Integer> mForwardMessageTypes = new HashSet<>();\n    private Set<Integer> mForwardExcludeMessageTypes = new HashSet<>();\n    private String mMentionForwardUrl = null;\n    private int mBlacklistStrategy = 0; //黑名单中时，0失败，1吞掉。\n    private boolean mBlacklistAllowSend2Black = true;\n    private boolean mNoForwardAdminMessage = false;\n    private boolean mAllowSend2ForbiddenUser = false;\n\n    private String mRemoteSensitiveServerUrl = null;\n    private Set<Integer> mRemoteSensitiveMessageTypes;\n    private boolean mWaitRemoteSensitiveServerResponse = false;\n\n    public SendMessageHandler() {\n        super();\n\n        mForwardUrl = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_Url);\n        if (!StringUtil.isNullOrEmpty(mForwardUrl)) {\n            String forwardTypes = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_Types);\n            parseTypes(mForwardMessageTypes, forwardTypes);\n            String excludeTypes = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_Exclude_Types);\n            parseTypes(mForwardExcludeMessageTypes, excludeTypes);\n        }\n        mSensitiveMessageForwardUrl = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Sensitive_Forward_Url);\n        mMentionForwardUrl = mServer.getConfig().getProperty(BrokerConstants.MESSAGE_MentionMsg_Forward_Url);\n\n        try {\n            mSensitiveType = Integer.parseInt(mServer.getConfig().getProperty(BrokerConstants.SENSITIVE_Filter_Type));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        try {\n            mBlacklistStrategy = Integer.parseInt(mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Blacklist_Strategy));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        try {\n            mBlacklistAllowSend2Black = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.MESSAGE_Blacklist_Allow_Send, \"true\"));\n        } catch (Exception e) {\n        }\n\n        try {\n            mRemoteSensitiveServerUrl = mServer.getConfig().getProperty(BrokerConstants.SENSITIVE_Remote_Server_URL);\n            if(!StringUtil.isNullOrEmpty(mRemoteSensitiveServerUrl)) {\n                mWaitRemoteSensitiveServerResponse = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.SENSITIVE_Remote_Fail_When_Matched, \"false\"));\n                String types = mServer.getConfig().getProperty(BrokerConstants.SENSITIVE_Remote_Message_Type, \"\");\n                mRemoteSensitiveMessageTypes = new HashSet<>();\n                if(!StringUtil.isNullOrEmpty(types)) {\n                    String[] ts = types.split(\",\");\n                    for (String t:ts) {\n                        mRemoteSensitiveMessageTypes.add(Integer.parseInt(t.trim()));\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        try {\n            mNoForwardAdminMessage = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.MESSAGE_NO_Forward_Admin_Message, \"false\"));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        try {\n            mAllowSend2ForbiddenUser = Boolean.parseBoolean(mServer.getConfig().getProperty(BrokerConstants.MESSAGES_ALLOW_SEND_TO_FORBIDDEN_USER, \"false\"));\n        } catch (Exception e) {}\n    }\n\n    private void parseTypes(Collection<Integer> collection, String types) {\n        try {\n            if (!StringUtil.isNullOrEmpty(types)) {\n                String[] tss = types.split(\",\");\n                for (String ts:tss) {\n                    if(ts.contains(\"-\")) {\n                        String[] ss = ts.split(\"-\");\n                        if(ss.length == 2) {\n                            int begin = Integer.parseInt(ss[0]);\n                            int end = Integer.parseInt(ss[1]);\n                            for (int i = begin; i <= end ; i++) {\n                                collection.add(i);\n                            }\n                        }\n                    } else {\n                        collection.add(Integer.parseInt(ts.trim()));\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.Message message, Qos1PublishHandler.IMCallback callback) {\n        ErrorCode errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        if (message != null) {\n            if(message.getContent().getContent().length() +\n                message.getContent().getSearchableContent().length() +\n                message.getContent().getData().size() +\n                message.getContent().getExtra().length() +\n                message.getContent().getPushContent().length() +\n                message.getContent().getPushData().length() > 64 * 1024) {\n                return ErrorCode.ERROR_CODE_MESSAGE_TOO_LARGE;\n            }\n\n            boolean ignoreMsg = false;\n            if (!isAdmin) {  //admin do not check the right\n                // 不能在端上直接发送撤回和群通知\n                if (message.getContent().getType() == 80 || message.getContent().getType() == 81 || (message.getContent().getType() >= 100 && message.getContent().getType() < 200)) {\n                    return ErrorCode.INVALID_PARAMETER;\n                }\n\n                if(m_messagesStore.getClientForbiddenSendTypes().contains(message.getContent().getType())) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n\n                int userStatus = m_messagesStore.getUserStatus(fromUser);\n                if (userStatus == ProtoConstants.UserStatus.Muted || userStatus == ProtoConstants.UserStatus.Forbidden) {\n                    if(!m_messagesStore.getGlobalMuteExceptionTypes().contains(message.getContent().getType())) {\n                        return ErrorCode.ERROR_CODE_FORBIDDEN_SEND_MSG;\n                    }\n                }\n\n                if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Private) {\n                    if(!m_messagesStore.getBlackListExceptionTypes().contains(message.getContent().getType())) {\n                        errorCode = m_messagesStore.isAllowUserMessage(message.getConversation().getTarget(), fromUser, message.getConversation().getLine());\n                        if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                            if (errorCode == ErrorCode.ERROR_CODE_IN_BLACK_LIST && mBlacklistStrategy != ProtoConstants.BlacklistStrategy.Message_Reject) {\n                                ignoreMsg = true;\n                                errorCode = ErrorCode.ERROR_CODE_SUCCESS;\n                            } else {\n                                return errorCode;\n                            }\n                        }\n\n                        if(!mBlacklistAllowSend2Black) {\n                            errorCode = m_messagesStore.isBlacked(fromUser, message.getConversation().getTarget());\n                            if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                                return errorCode;\n                            }\n                        }\n                    }\n\n                    if (!mAllowSend2ForbiddenUser) {\n                        userStatus = m_messagesStore.getUserStatus(message.getConversation().getTarget());\n                        if (userStatus == ProtoConstants.UserStatus.Forbidden) {\n                            return ErrorCode.ERROR_CODE_USER_FORBIDDEN;\n                        }\n                    }\n                }\n\n                if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Group ) {\n                    if(!m_messagesStore.getGroupMuteExceptionTypes().contains(message.getContent().getType())) {\n                        errorCode = m_messagesStore.canSendMessageInGroup(fromUser, message.getConversation().getTarget());\n                        if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                            return errorCode;\n                        }\n                    }\n                } else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_ChatRoom) {\n                    if(!m_messagesStore.getGroupMuteExceptionTypes().contains(message.getContent().getType())) {\n                        if (!m_messagesStore.checkUserClientInChatroom(fromUser, clientID, message.getConversation().getTarget())) {\n                            return ErrorCode.ERROR_CODE_NOT_IN_CHATROOM;\n                        }\n                    }\n                } else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Channel) {\n                    if(!m_messagesStore.getGroupMuteExceptionTypes().contains(message.getContent().getType())) {\n                        if (!m_messagesStore.canSendMessageInChannel(fromUser, message.getConversation().getTarget())) {\n                            return ErrorCode.ERROR_CODE_NOT_IN_CHANNEL;\n                        }\n                    }\n                }\n            } else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Group) {\n                if(m_messagesStore.getGroupInfo(message.getConversation().getTarget()) == null) {\n                    return ErrorCode.ERROR_CODE_NOT_EXIST;\n                }\n            } else if (message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Channel) {\n                WFCMessage.ChannelInfo channelData = m_messagesStore.getChannelInfo(message.getConversation().getTarget());\n                if(channelData == null || channelData.getStatus() == ProtoConstants.ChannelState.Channel_State_Mask_Deleted) {\n                    return ErrorCode.ERROR_CODE_NOT_EXIST;\n                }\n            }\n\n            long timestamp = System.currentTimeMillis();\n            final long messageId;\n            try {\n                messageId = MessageShardingUtil.generateId();\n            } catch (Exception e) {\n                e.printStackTrace();\n                return ErrorCode.ERROR_CODE_SERVER_ERROR;\n            }\n            message = message.toBuilder().setFromUser(fromUser).setMessageId(messageId).setServerTimestamp(timestamp).build();\n\n\n            if (!StringUtil.isNullOrEmpty(mForwardUrl) && (mForwardMessageTypes.isEmpty() || mForwardMessageTypes.contains(message.getContent().getType())) && !(isAdmin && mNoForwardAdminMessage) && !mForwardExcludeMessageTypes.contains(message.getContent().getType())) {\n                publisher.forwardMessage(message, mForwardUrl, clientID);\n            }\n\n            if(!StringUtil.isNullOrEmpty(mMentionForwardUrl) && message.hasContent() && message.getContent().getMentionedType() != 0 && !(isAdmin && mNoForwardAdminMessage)) {\n                publisher.forwardMessage(message, mMentionForwardUrl, clientID);\n            }\n\n            if (!isAdmin) {\n                if(StringUtil.isNullOrEmpty(mRemoteSensitiveServerUrl)) {\n                    Set<String> matched = m_messagesStore.handleSensitiveWord(message.getContent().getSearchableContent());\n                    if (matched != null && !matched.isEmpty()) {\n                        m_messagesStore.storeSensitiveMessage(message);\n                        if (!StringUtil.isNullOrEmpty(mSensitiveMessageForwardUrl)) {\n                            publisher.forwardMessage(message, mSensitiveMessageForwardUrl, clientID);\n                        }\n                        if (mSensitiveType == 0) {\n                            errorCode = ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;\n                        } else if (mSensitiveType == 1) {\n                            ignoreMsg = true;\n                        } else if (mSensitiveType == 2) {\n                            String text = message.getContent().getSearchableContent();\n                            for (String word : matched) {\n                                text = text.replace(word, \"***\");\n                            }\n                            message = message.toBuilder().setContent(message.getContent().toBuilder().setSearchableContent(text).build()).build();\n                        }\n                    }\n                } else {\n                    if(mRemoteSensitiveMessageTypes.contains(message.getContent().getType())) {\n                        final WFCMessage.Message finalMsg = message;\n                        publisher.forwardMessageWithCallback(message, clientID, mRemoteSensitiveServerUrl, new HttpUtils.HttpCallback() {\n                            @Override\n                            public void onSuccess(String content) {\n                                if(StringUtil.isNullOrEmpty(content)) {\n                                    saveAndPublish(fromUser, clientID, finalMsg, requestSourceType);\n                                } else {\n                                    MessagePayload payload = GsonUtil.gson.fromJson(content, MessagePayload.class);\n                                    if (payload != null && payload.getType() > 0) {\n                                        WFCMessage.Message newMsg = finalMsg.toBuilder().setContent(payload.toProtoMessageContent()).build();\n                                        saveAndPublish(fromUser, clientID, newMsg, requestSourceType);\n                                    } else {\n                                        LOG.error(\"Response content {} from censor is invalid payload, ignore response and send original message\", content);\n                                        saveAndPublish(fromUser, clientID, finalMsg, requestSourceType);\n                                    }\n                                }\n                                if(mWaitRemoteSensitiveServerResponse) {\n                                    ByteBuf ackPayload = Unpooled.buffer(21);\n                                    ErrorCode errorCode = ERROR_CODE_SUCCESS;\n                                    ackPayload.writeByte(errorCode.getCode());\n                                    ackPayload.writeLong(messageId);\n                                    ackPayload.writeLong(timestamp);\n                                    callback.onIMHandled(ErrorCode.ERROR_CODE_SUCCESS, ackPayload);\n                                }\n                            }\n\n                            @Override\n                            public void onFailure(int statusCode, String errorMessage) {\n                                ByteBuf ackPayload = null;\n                                ErrorCode errorCode = ERROR_CODE_SUCCESS;\n                                if(statusCode == 403) {\n                                    if(mWaitRemoteSensitiveServerResponse) {\n                                        errorCode = ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;\n                                        ackPayload = Unpooled.buffer(1);\n                                        ackPayload.writeByte(errorCode.getCode());\n                                    }\n                                } else {\n                                    LOG.warn(\"Failed to censor message with status {}, errorMessage {}. Send the original message\", statusCode, errorMessage);\n                                    saveAndPublish(fromUser, clientID, finalMsg, requestSourceType);\n\n                                    if(mWaitRemoteSensitiveServerResponse) {\n                                        errorCode = ERROR_CODE_SUCCESS;\n                                        ackPayload = Unpooled.buffer(21);\n                                        ackPayload.writeByte(errorCode.getCode());\n                                        ackPayload.writeLong(messageId);\n                                        ackPayload.writeLong(timestamp);\n                                    }\n                                }\n\n                                if(mWaitRemoteSensitiveServerResponse) {\n                                    callback.onIMHandled(errorCode, ackPayload);\n                                }\n                            }\n                        });\n\n                        if(mWaitRemoteSensitiveServerResponse) {\n                            ackPayload.clear();\n                            return ErrorCode.INVALID_ASYNC_HANDLING;\n                        } else {\n                            ackPayload = ackPayload.capacity(20);\n                            ackPayload.writeLong(messageId);\n                            ackPayload.writeLong(timestamp);\n                            return ErrorCode.ERROR_CODE_SUCCESS;\n                        }\n                    }\n                }\n            }\n\n            if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {\n                if(!ignoreMsg) {\n                    saveAndPublish(fromUser, clientID, message, requestSourceType);\n                }\n                ackPayload = ackPayload.capacity(20);\n                ackPayload.writeLong(messageId);\n                ackPayload.writeLong(timestamp);\n            }\n        } else {\n            errorCode = ErrorCode.ERROR_CODE_INVALID_MESSAGE;\n        }\n        return errorCode;\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/SetFriendAliasRequestHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.SetFriendAliasTopic)\npublic class SetFriendAliasRequestHandler extends GroupHandler<WFCMessage.AddFriendRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.AddFriendRequest request, Qos1PublishHandler.IMCallback callback) {\n        long[] head = new long[1];\n        ErrorCode errorCode = m_messagesStore.setFriendAliasRequest(fromUser, request.getTargetUid(), request.getReason(), head);\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            publisher.publishNotification(IMTopic.NotifyFriendTopic, fromUser, head[0]);\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/SetFriendExtraHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.SetFriendExtraTopic)\npublic class SetFriendExtraHandler extends IMHandler<WFCMessage.StringPair> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.StringPair request, Qos1PublishHandler.IMCallback callback) {\n        long[] heads = new long[1];\n        ErrorCode errorCode = m_messagesStore.setFriendExtraRequest(fromUser, request.getKey(), request.getValue(), heads);\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            publisher.publishNotification(IMTopic.NotifyFriendTopic, fromUser, heads[0], clientID);\n        }\n\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/SetGroupManagerHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.GroupNotificationBinaryContent;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.SetGroupManagerTopic)\npublic class SetGroupManagerHandler extends GroupHandler<WFCMessage.SetGroupManagerRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.SetGroupManagerRequest request, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !m_messagesStore.isAllowClientCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot && !m_messagesStore.isAllowRobotCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {\n            int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();\n            if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Set_Group_Manage) > 0) {\n                return ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n        }\n\n        ErrorCode errorCode = m_messagesStore.setGroupManager(fromUser, request.getGroupId(), request.getType(), request.getUserIdList(), isAdmin);\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());\n            } else {\n                WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, request.getType() + \"\", request.getUserIdList()).getSetGroupManagerNotifyContent();\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);\n            }\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/SyncFriendRequestUnreadHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.RriendRequestUnreadSyncTopic)\npublic class SyncFriendRequestUnreadHandler extends GroupHandler<WFCMessage.Version> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.Version request, Qos1PublishHandler.IMCallback callback) {\n            long[] head = new long[1];\n            ErrorCode errorCode = m_messagesStore.SyncFriendRequestUnread(fromUser, request.getVersion(), head);\n            if (errorCode == ERROR_CODE_SUCCESS) {\n                publisher.publishNotification(IMTopic.NotifyFriendRequestTopic, fromUser, head[0]);\n            }\n            return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/TransferChannelHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n@Handler(IMTopic.TransferChannelInfoTopic)\npublic class TransferChannelHandler extends GroupHandler<WFCMessage.TransferChannel> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.TransferChannel request, Qos1PublishHandler.IMCallback callback) {\n        ErrorCode errorCode = m_messagesStore.transferChannel(fromUser, request.getChannelId(), request.getNewOwner());\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/TransferGroupHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.pojos.GroupNotificationBinaryContent;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\n\n@Handler(IMTopic.TransferGroupTopic)\npublic class TransferGroupHandler extends GroupHandler<WFCMessage.TransferGroupRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.TransferGroupRequest request, Qos1PublishHandler.IMCallback callback) {\n        boolean isAdmin = requestSourceType == ProtoConstants.RequestSourceType.Request_From_Admin;\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_User && !m_messagesStore.isAllowClientCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n        if(request.hasNotifyContent() && request.getNotifyContent().getType() > 0 && requestSourceType == ProtoConstants.RequestSourceType.Request_From_Robot && !m_messagesStore.isAllowRobotCustomGroupNotification()) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_User) {\n            int forbiddenClientOperation = m_messagesStore.getGroupForbiddenClientOperation();\n            if((forbiddenClientOperation & ProtoConstants.ForbiddenClientGroupOperationMask.Forbidden_Transfer_Group) > 0) {\n                return ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n        }\n\n        ErrorCode errorCode = m_messagesStore.transferGroup(fromUser, request.getGroupId(), request.getNewOwner(), isAdmin);\n        if (errorCode == ERROR_CODE_SUCCESS) {\n            if (request.hasNotifyContent() && request.getNotifyContent().getType() > 0) {\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), request.getNotifyContent());\n            } else {\n                WFCMessage.MessageContent content = new GroupNotificationBinaryContent(request.getGroupId(), fromUser, null, request.getNewOwner()).getTransferGroupNotifyContent();\n                sendGroupNotification(fromUser, request.getGroupId(), request.getToLineList(), content);\n            }\n        }\n        return errorCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/UploadDeviceTokenHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\n\n@Handler(IMTopic.UploadDeviceTokenTopic)\npublic class UploadDeviceTokenHandler extends IMHandler<WFCMessage.UploadDeviceTokenRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.UploadDeviceTokenRequest request, Qos1PublishHandler.IMCallback callback) {\n            MemorySessionStore.Session session = m_sessionsStore.getSession(clientID);\n            session.setPlatform(request.getPlatform());\n            session.setAppName(request.getAppName());\n            if (request.getPlatform() == ProtoConstants.Platform.Platform_iOS && request.getPushType() == 2) {\n                LOG.info(\"Set device token, userId {}\", fromUser);\n                session.setVoipDeviceToken(request.getDeviceToken());\n                m_sessionsStore.updateSessionToken(session, true);\n            } else {\n                LOG.info(\"Set device token, userId {}, platform {}, pushType {}\", fromUser, session.getPlatform(), request.getPushType());\n                session.setDeviceToken(request.getDeviceToken());\n                session.setPushType(request.getPushType());\n                m_sessionsStore.updateSessionToken(session, false);\n                m_sessionsStore.cleanDuplatedToken(session.getClientID(), session.getPushType(), session.getDeviceToken(), false, session.getAppName());\n            }\n\n            return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/imhandler/UserSearchHandler.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.imhandler;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.spi.impl.Qos1PublishHandler;\nimport io.netty.buffer.ByteBuf;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.IMTopic;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n@Handler(IMTopic.UserSearchTopic)\npublic class UserSearchHandler extends IMHandler<WFCMessage.SearchUserRequest> {\n    @Override\n    public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.SearchUserRequest request, Qos1PublishHandler.IMCallback callback) {\n        List<WFCMessage.User> users = new ArrayList<>();\n        ErrorCode errorCode = m_messagesStore.searchUser(fromUser, request.getKeyword(), request.getFuzzy(), request.getType(), request.getPage(), users);\n        if(errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n            return errorCode;\n        }\n        WFCMessage.SearchUserResult.Builder builder = WFCMessage.SearchUserResult.newBuilder();\n        builder.addAllEntry(users);\n        byte[] data = builder.build().toByteArray();\n        ackPayload.ensureWritable(data.length).writeBytes(data);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/interception/InterceptHandler.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.interception;\n\nimport io.moquette.interception.messages.*;\nimport io.netty.handler.codec.mqtt.MqttMessage;\n\n/**\n * This interface is used to inject code for intercepting broker events.\n * <p>\n * The events can act only as observers.\n * <p>\n * Almost every method receives a subclass of {@link MqttMessage}, except <code>onDisconnect</code>\n * that receives the client id string and <code>onSubscribe</code> and <code>onUnsubscribe</code>\n * that receive a {@link Subscription} object.\n */\npublic interface InterceptHandler {\n\n    Class<?>[] ALL_MESSAGE_TYPES = {InterceptConnectMessage.class, InterceptDisconnectMessage.class,\n            InterceptConnectionLostMessage.class, InterceptPublishMessage.class, InterceptAcknowledgedMessage.class};\n\n    /**\n     * Returns the identifier of this intercept handler.\n     *\n     * @return\n     */\n    String getID();\n\n    /**\n     * Returns the InterceptMessage subtypes that this handler can process. If the result is null or\n     * equal to ALL_MESSAGE_TYPES, all the message types will be processed.\n     *\n     * @return\n     */\n    Class<?>[] getInterceptedMessageTypes();\n\n    void onConnect(InterceptConnectMessage msg);\n\n    void onDisconnect(InterceptDisconnectMessage msg);\n\n    void onConnectionLost(InterceptConnectionLostMessage msg);\n\n    void onPublish(InterceptPublishMessage msg);\n\n    void onMessageAcknowledged(InterceptAcknowledgedMessage msg);\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/interception/Interceptor.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.interception;\n\nimport io.moquette.interception.messages.InterceptAcknowledgedMessage;\nimport io.netty.handler.codec.mqtt.MqttConnectMessage;\nimport io.netty.handler.codec.mqtt.MqttPublishMessage;\n\n/**\n * This interface is to be used internally by the broker components.\n * <p>\n * An interface is used instead of a class to allow more flexibility in changing an implementation.\n * <p>\n * Interceptor implementations forward notifications to a <code>InterceptHandler</code>, that is\n * normally a field. So, the implementations should act as a proxy to a custom intercept handler.\n *\n * @see InterceptHandler\n */\npublic interface Interceptor {\n\n    void notifyClientConnected(MqttConnectMessage msg);\n\n    void notifyClientDisconnected(String clientID, String username);\n\n    void notifyClientConnectionLost(String clientID, String username);\n\n    void notifyMessageAcknowledged(InterceptAcknowledgedMessage msg);\n\n    void addInterceptHandler(InterceptHandler interceptHandler);\n\n    void removeInterceptHandler(InterceptHandler interceptHandler);\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/interception/messages/InterceptAbstractMessage.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.interception.messages;\n\nimport io.netty.handler.codec.mqtt.MqttMessage;\nimport io.netty.handler.codec.mqtt.MqttQoS;\n\npublic abstract class InterceptAbstractMessage implements InterceptMessage {\n\n    private final MqttMessage msg;\n\n    InterceptAbstractMessage(MqttMessage msg) {\n        this.msg = msg;\n    }\n\n    public boolean isRetainFlag() {\n        return msg.fixedHeader().isRetain();\n    }\n\n    public boolean isDupFlag() {\n        return msg.fixedHeader().isDup();\n    }\n\n    public MqttQoS getQos() {\n        return msg.fixedHeader().qosLevel();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/interception/messages/InterceptAcknowledgedMessage.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.interception.messages;\n\nimport static io.moquette.spi.IMessagesStore.StoredMessage;\n\npublic class InterceptAcknowledgedMessage implements InterceptMessage {\n\n    private final StoredMessage msg;\n    private final String username;\n    private final String topic;\n    private final int packetID;\n\n    public InterceptAcknowledgedMessage(StoredMessage msg, String topic, String username, int packetID) {\n        this.msg = msg;\n        this.username = username;\n        this.topic = topic;\n        this.packetID = packetID;\n    }\n\n    public StoredMessage getMsg() {\n        return msg;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public String getTopic() {\n        return topic;\n    }\n\n    public int getPacketID() {\n        return packetID;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/interception/messages/InterceptConnectMessage.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.interception.messages;\n\nimport io.netty.handler.codec.mqtt.MqttConnectMessage;\n\npublic class InterceptConnectMessage extends InterceptAbstractMessage {\n\n    private final MqttConnectMessage msg;\n\n    public InterceptConnectMessage(MqttConnectMessage msg) {\n        super(msg);\n        this.msg = msg;\n    }\n\n    public String getClientID() {\n        return msg.payload().clientIdentifier();\n    }\n\n    public boolean isCleanSession() {\n        return msg.variableHeader().isCleanSession();\n    }\n\n    public int getKeepAlive() {\n        return msg.variableHeader().keepAliveTimeSeconds();\n    }\n\n    public boolean isPasswordFlag() {\n        return msg.variableHeader().hasPassword();\n    }\n\n    public byte getProtocolVersion() {\n        return (byte) msg.variableHeader().version();\n    }\n\n    public String getProtocolName() {\n        return msg.variableHeader().name();\n    }\n\n    public boolean isUserFlag() {\n        return msg.variableHeader().hasUserName();\n    }\n\n    public boolean isWillFlag() {\n        return msg.variableHeader().isWillFlag();\n    }\n\n    public byte getWillQos() {\n        return (byte) msg.variableHeader().willQos();\n    }\n\n    public boolean isWillRetain() {\n        return msg.variableHeader().isWillRetain();\n    }\n\n    public String getUsername() {\n        return msg.payload().userName();\n    }\n\n    public byte[] getPassword() {\n        return msg.payload().passwordInBytes();\n    }\n\n    public String getWillTopic() {\n        return msg.payload().willTopic();\n    }\n\n    public byte[] getWillMessage() {\n        return msg.payload().willMessage().getBytes();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/interception/messages/InterceptConnectionLostMessage.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.interception.messages;\n\npublic class InterceptConnectionLostMessage implements InterceptMessage {\n\n    private final String clientID;\n    private final String username;\n\n    public InterceptConnectionLostMessage(String clientID, String username) {\n        this.clientID = clientID;\n        this.username = username;\n    }\n\n    public String getClientID() {\n        return clientID;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/interception/messages/InterceptDisconnectMessage.java",
    "content": "/*\r\n * Copyright (c) 2012-2017 The original author or authors\r\n * ------------------------------------------------------\r\n * All rights reserved. This program and the accompanying materials\r\n * are made available under the terms of the Eclipse Public License v1.0\r\n * and Apache License v2.0 which accompanies this distribution.\r\n *\r\n * The Eclipse Public License is available at\r\n * http://www.eclipse.org/legal/epl-v10.html\r\n *\r\n * The Apache License v2.0 is available at\r\n * http://www.opensource.org/licenses/apache2.0.php\r\n *\r\n * You may elect to redistribute this code under either of these licenses.\r\n */\r\n\r\npackage io.moquette.interception.messages;\r\n\r\npublic class InterceptDisconnectMessage implements InterceptMessage {\r\n\r\n    private final String clientID;\r\n    private final String username;\r\n\r\n    public InterceptDisconnectMessage(String clientID, String username) {\r\n        this.clientID = clientID;\r\n        this.username = username;\r\n    }\r\n\r\n    public String getClientID() {\r\n        return clientID;\r\n    }\r\n\r\n    public String getUsername() {\r\n        return username;\r\n    }\r\n}\r\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/interception/messages/InterceptMessage.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.interception.messages;\n\n/**\n * An interface that sets the root of the interceptor messages type hierarchy.\n */\npublic interface InterceptMessage {\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/interception/messages/InterceptPublishMessage.java",
    "content": "/*\r\n * Copyright (c) 2012-2017 The original author or authors\r\n * ------------------------------------------------------\r\n * All rights reserved. This program and the accompanying materials\r\n * are made available under the terms of the Eclipse Public License v1.0\r\n * and Apache License v2.0 which accompanies this distribution.\r\n *\r\n * The Eclipse Public License is available at\r\n * http://www.eclipse.org/legal/epl-v10.html\r\n *\r\n * The Apache License v2.0 is available at\r\n * http://www.opensource.org/licenses/apache2.0.php\r\n *\r\n * You may elect to redistribute this code under either of these licenses.\r\n */\r\n\r\npackage io.moquette.interception.messages;\r\n\r\nimport io.netty.buffer.ByteBuf;\r\nimport io.netty.handler.codec.mqtt.MqttPublishMessage;\r\n\r\npublic class InterceptPublishMessage extends InterceptAbstractMessage {\r\n\r\n    private final MqttPublishMessage msg;\r\n    private final String clientID;\r\n    private final String username;\r\n\r\n    public InterceptPublishMessage(MqttPublishMessage msg, String clientID, String username) {\r\n        super(msg);\r\n        this.msg = msg;\r\n        this.clientID = clientID;\r\n        this.username = username;\r\n    }\r\n\r\n    public String getTopicName() {\r\n        return msg.variableHeader().topicName();\r\n    }\r\n\r\n    public ByteBuf getPayload() {\r\n        return msg.payload();\r\n    }\r\n\r\n    public String getClientID() {\r\n        return clientID;\r\n    }\r\n\r\n    public String getUsername() {\r\n        return username;\r\n    }\r\n}\r\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/logging/LoggingUtils.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.logging;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport io.moquette.interception.InterceptHandler;\n\npublic final class LoggingUtils {\n\n    public static <T extends InterceptHandler> Collection<String> getInterceptorIds(Collection<T> handlers) {\n        Collection<String> result = new ArrayList<>(handlers.size());\n        for (T handler : handlers) {\n            result.add(handler.getID());\n        }\n        return result;\n    }\n\n    private LoggingUtils() {\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/ChannelLoader.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.persistence;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.core.MapStore;\nimport io.moquette.server.Server;\n\nimport java.util.Collection;\nimport java.util.Map;\n\npublic class ChannelLoader implements MapStore<String, WFCMessage.ChannelInfo> {\n    @Override\n    public void store(String s, WFCMessage.ChannelInfo channelInfo) {\n        getDatabaseStore().updateChannelInfo(channelInfo);\n    }\n\n    @Override\n    public void storeAll(Map<String, WFCMessage.ChannelInfo> map) {\n\n    }\n\n    @Override\n    public void delete(String s) {\n        getDatabaseStore().removeChannelInfo(s);\n    }\n\n    @Override\n    public void deleteAll(Collection<String> collection) {\n\n    }\n\n    private DatabaseStore getDatabaseStore() {\n        return Server.getServer().getStore().messagesStore().getDatabaseStore();\n    }\n\n    @Override\n    public WFCMessage.ChannelInfo load(String key) {\n        return getDatabaseStore().getPersistChannelInfo(key);\n    }\n\n    @Override\n    public Map<String, WFCMessage.ChannelInfo> loadAll(Collection<String> keys) {\n        return null;\n    }\n\n    @Override\n    public Iterable<String> loadAllKeys() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/ChatroomLoader.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.persistence;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.core.MapStore;\nimport io.moquette.server.Server;\n\nimport java.util.Collection;\nimport java.util.Map;\n\npublic class ChatroomLoader implements MapStore<String, WFCMessage.ChatroomInfo> {\n    private DatabaseStore getDatabaseStore() {\n        return Server.getServer().getStore().messagesStore().getDatabaseStore();\n    }\n\n    /**\n     * Loads the value of a given key. If distributed map doesn't contain the value\n     * for the given key then Hazelcast will call implementation's load (key) method\n     * to obtain the value. Implementation can use any means of loading the given key;\n     * such as an O/R mapping tool, simple SQL or reading a file etc.\n     *\n     * @param key@return value of the key, value cannot be null\n     */\n    @Override\n    public WFCMessage.ChatroomInfo load(String key) {\n        return getDatabaseStore().getPersistChatroomInfo(key);\n    }\n\n    /**\n     * Loads given keys. This is batch load operation so that implementation can\n     * optimize the multiple loads.\n     * <p>\n     * For any key in the input keys, there should be a single mapping in the resulting map. Also the resulting\n     * map should not have any keys that are not part of the input keys.\n     * <p>\n     * The given collection should not contain any <code>null</code> keys.\n     * The returned Map should not contain any <code>null</code> keys or values.\n     *\n     * @param keys keys of the values entries to load\n     * @return map of loaded key-value pairs.\n     */\n    @Override\n    public Map<String, WFCMessage.ChatroomInfo> loadAll(Collection<String> keys) {\n        return null;\n    }\n\n    @Override\n    public Iterable<String> loadAllKeys() {\n        return null;\n    }\n\n    @Override\n    public void store(String s, WFCMessage.ChatroomInfo chatroomInfo) {\n        getDatabaseStore().updateChatroomInfo(s, chatroomInfo);\n    }\n\n    @Override\n    public void storeAll(Map<String, WFCMessage.ChatroomInfo> map) {\n\n    }\n\n    @Override\n    public void delete(String s) {\n        getDatabaseStore().removeChatroomInfo(s);\n    }\n\n    @Override\n    public void deleteAll(Collection<String> collection) {\n\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/DatabaseStore.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.persistence;\n\nimport cn.wildfirechat.pojos.SystemSettingPojo;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.server.ThreadPoolExecutorWrapper;\nimport com.hazelcast.core.HazelcastInstance;\nimport com.hazelcast.core.MultiMap;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.model.FriendData;\nimport io.moquette.server.Server;\nimport io.moquette.spi.ClientSession;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.DBUtil;\nimport win.liyufan.im.MessageBundle;\nimport win.liyufan.im.MessageShardingUtil;\nimport win.liyufan.im.Utility;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.security.MessageDigest;\nimport java.sql.*;\nimport java.util.*;\nimport java.util.function.Function;\n\n\nimport static cn.wildfirechat.common.IMExceptionEvent.EventType.RDBS_Exception;\nimport static cn.wildfirechat.proto.ProtoConstants.PersistFlag.Transparent;\nimport static cn.wildfirechat.proto.ProtoConstants.UserSearchUserType.UserSearchUserType_ONLY_ROBOT;\nimport static cn.wildfirechat.proto.ProtoConstants.UserSearchUserType.UserSearchUserType_ONLY_USER;\nimport static io.moquette.BrokerConstants.GROUP_INFO_MARK_DELETION;\nimport static io.moquette.server.Constants.MAX_MESSAGE_QUEUE;\nimport static cn.wildfirechat.proto.ProtoConstants.SearchUserType.*;\nimport static win.liyufan.im.UserSettingScope.kUserSettingPrivacySearchable;\n\npublic class DatabaseStore {\n    private static final Logger LOG = LoggerFactory.getLogger(DatabaseStore.class);\n    private final ThreadPoolExecutorWrapper mScheduler;\n    private boolean disableRemoteMessageSearch = false;\n    private boolean encryptMessage = false;\n    private boolean keepGroupInfo = false;\n    public void setDisableRemoteMessageSearch(boolean disableRemoteMessageSearch) {\n        this.disableRemoteMessageSearch = disableRemoteMessageSearch;\n    }\n\n    public void setEncryptMessage(boolean encryptMessage) {\n        this.encryptMessage = encryptMessage;\n    }\n\n    public DatabaseStore(ThreadPoolExecutorWrapper scheduler) {\n        this.mScheduler = scheduler;\n        try {\n            keepGroupInfo = Boolean.parseBoolean(Server.getServer().getConfig().getProperty(GROUP_INFO_MARK_DELETION, \"false\"));\n        } catch (Exception e) {\n\n        }\n    }\n\n    TreeMap<Long, Long> reloadUserMessageMaps(String userId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        TreeMap<Long, Long> out = new TreeMap<>();\n        try {\n            connection = DBUtil.getConnection();\n\n            String sql = \"select `_seq`, `_mid` from \" + getUserMessageTable(userId) + \" where `_uid` = ? order by `_seq` DESC limit \" + MAX_MESSAGE_QUEUE;\n\n            statement = connection.prepareStatement(sql);\n\n            statement.setString(1, userId);\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                int index = 1;\n                long msgSeq = rs.getLong(index++);\n                long msgId = rs.getLong(index);\n                out.put(msgSeq, msgId);\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n\n        return out;\n    }\n\n    boolean updateSystemSetting(int id, String value, String desc) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"insert into t_settings \" +\n                \" (`id`, `_value`, `_desc`) values(?, ?, ?)\" +\n                \" ON DUPLICATE KEY UPDATE \" +\n                \"`_value` = ?,\" +\n                \"`_desc` = ?\";\n\n\n            statement = connection.prepareStatement(sql);\n            int index = 1;\n            statement.setLong(index++, id);\n            statement.setString(index++, value);\n            statement.setString(index++, desc);\n            statement.setString(index++, value);\n            statement.setString(index++, desc);\n\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n            return true;\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n        return false;\n    }\n\n    SystemSettingPojo getSystemSetting(int id) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_value`, `_desc` from t_settings where `id` = ?\";\n\n            statement = connection.prepareStatement(sql);\n            int index = 1;\n            statement.setLong(index++, id);\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                SystemSettingPojo out = new SystemSettingPojo();\n                index = 1;\n\n                out.id = id;\n\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                out.value = value;\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                out.desc = value;\n\n               return out;\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n    List<WFCMessage.User> searchUserByNameMobileUserId(String keyword, int searchType, int userType) {\n        ArrayList<WFCMessage.User> out = new ArrayList<>();\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_uid`, `_name`\" +\n                \", `_display_name`\" +\n                \", `_portrait`\" +\n                \", `_mobile`\" +\n                \", `_gender`\" +\n                \", `_email`\" +\n                \", `_address`\" +\n                \", `_company`\" +\n                \", `_social`\" +\n                \", `_extra`\" +\n                \", `_dt`, `_type` from t_user\";\n\n            int sqlParaCount = 1;\n            if(searchType == SearchUserType_Name) {\n                sql += \" where `_name` = ? \";\n            } else if(searchType == SearchUserType_Mobile) {\n                sql += \" where `_mobile` = ? \";\n            } else if(searchType == SearchUserType_UserId) {\n                sql += \" where `_uid` = ? \";\n            } else if(searchType == SearchUserType_Name_Mobile || searchType == SearchUserType_Name_Mobile_DisplayName) {\n                sqlParaCount = 2;\n                sql += \" where (`_name` = ? or `_mobile` = ?) \";\n            } else {\n                sqlParaCount = 3;\n                sql += \" where (`_name` = ? or `_mobile` = ? or `_uid` = ?) \";\n            }\n\n            if(userType == UserSearchUserType_ONLY_USER) {\n                sql += \" and _type <> 2 \"; //can not search device\n                sql += \" and _type <> 1 \";\n            } else if(userType == UserSearchUserType_ONLY_ROBOT) {\n                sql += \" and _type = 1 \";\n            } else {\n                sql += \" and _type <> 2 \"; //can not search device\n            }\n            sql += \" and _deleted = 0 \";\n\n            if(searchType == SearchUserType_Name || searchType == SearchUserType_Mobile || searchType == SearchUserType_UserId) {\n                sql += \" limit 1\";\n            } else if(searchType == SearchUserType_Name_Mobile || searchType == SearchUserType_Name_Mobile_DisplayName) {\n                sql += \" limit 2\";\n            } else {\n                sql += \" limit 3\";\n            }\n\n            statement = connection.prepareStatement(sql);\n            for (int i = 0; i < sqlParaCount; i++) {\n                statement.setString(i+1, keyword);\n            }\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                WFCMessage.User.Builder builder = WFCMessage.User.newBuilder();\n                int index = 1;\n\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setUid(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setName(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setDisplayName(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setPortrait(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setMobile(value);\n\n                int gender = rs.getInt(index++);\n                builder.setGender(gender);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setEmail(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setAddress(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setCompany(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setSocial(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setExtra(value);\n\n                long longValue = rs.getLong(index++);\n                builder.setUpdateDt(longValue);\n\n                int type = rs.getInt(index++);\n                builder.setType( type);\n\n                WFCMessage.User user = builder.build();\n\n                out.add(user);\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n\n        List<WFCMessage.User> filter = new ArrayList<>();\n        for (WFCMessage.User user : out) {\n            WFCMessage.UserSettingEntry userSettingEntry = Server.getServer().getStore().messagesStore().getUserSetting(user.getUid(), kUserSettingPrivacySearchable, null);\n            if(userSettingEntry != null) {\n                int value = 0;\n                try {\n                    value = StringUtil.isNullOrEmpty(userSettingEntry.getValue())?0:Integer.parseInt(userSettingEntry.getValue());\n                } catch (NumberFormatException e) {\n                    e.printStackTrace();\n                }\n                if((value & ProtoConstants.DisableSearchMask.DisableSearchNameMask) > 0) {\n                    if (searchType == SearchUserType_Name) {\n                        filter.add(user);\n                        continue;\n                    } else if(searchType == SearchUserType_Name_Mobile || searchType == SearchUserType_Name_Mobile_DisplayName) {\n                        if(keyword.equals(user.getName())) {\n                            if(!keyword.equals(user.getMobile())) {\n                                filter.add(user);\n                                continue;\n                            } else if((value & ProtoConstants.DisableSearchMask.DisableSearchMobileMask) > 0) {\n                                filter.add(user);\n                                continue;\n                            }\n                        }\n                    } else if(searchType == SearchUserType_Name_Mobile_UserId) {\n                        if(keyword.equals(user.getName())) {\n                            if(keyword.equals(user.getMobile()) && keyword.equals(user.getUid())) {\n                                if((value & ProtoConstants.DisableSearchMask.DisableSearchMobileMask) > 0 && (value & ProtoConstants.DisableSearchMask.DisableSearchUserIdMask) > 0) {\n                                    filter.add(user);\n                                    continue;\n                                }\n                            } else if(keyword.equals(user.getMobile())) {\n                                if((value & ProtoConstants.DisableSearchMask.DisableSearchMobileMask) > 0) {\n                                    filter.add(user);\n                                    continue;\n                                }\n                            } else if(keyword.equals(user.getUid())) {\n                                if((value & ProtoConstants.DisableSearchMask.DisableSearchUserIdMask) > 0) {\n                                    filter.add(user);\n                                    continue;\n                                }\n                            } else {\n                                filter.add(user);\n                                continue;\n                            }\n                        }\n                    }\n                }\n\n\n                if((value & ProtoConstants.DisableSearchMask.DisableSearchMobileMask) > 0) {\n                    if (searchType == SearchUserType_Mobile) {\n                        filter.add(user);\n                        continue;\n                    } else if(searchType == SearchUserType_Name_Mobile || searchType == SearchUserType_Name_Mobile_DisplayName) {\n                        if(keyword.equals(user.getMobile())) {\n                            if(!keyword.equals(user.getName())) {\n                                filter.add(user);\n                                continue;\n                            } else if((value & ProtoConstants.DisableSearchMask.DisableSearchNameMask) > 0) {\n                                filter.add(user);\n                                continue;\n                            }\n                        }\n                    } else if(searchType == SearchUserType_Name_Mobile_UserId) {\n                        if(keyword.equals(user.getMobile())) {\n                            if(keyword.equals(user.getName()) && keyword.equals(user.getUid())) {\n                                if((value & ProtoConstants.DisableSearchMask.DisableSearchNameMask) > 0 && (value & ProtoConstants.DisableSearchMask.DisableSearchUserIdMask) > 0) {\n                                    filter.add(user);\n                                    continue;\n                                }\n                            } else if(keyword.equals(user.getName())) {\n                                if((value & ProtoConstants.DisableSearchMask.DisableSearchNameMask) > 0) {\n                                    filter.add(user);\n                                    continue;\n                                }\n                            } else if(keyword.equals(user.getUid())) {\n                                if((value & ProtoConstants.DisableSearchMask.DisableSearchUserIdMask) > 0) {\n                                    filter.add(user);\n                                    continue;\n                                }\n                            } else {\n                                filter.add(user);\n                                continue;\n                            }\n                        }\n                    }\n                }\n\n                if((value & ProtoConstants.DisableSearchMask.DisableSearchUserIdMask) > 0) {\n                    if (searchType == SearchUserType_UserId) {\n                        filter.add(user);\n                        continue;\n                    } else if(searchType == SearchUserType_Name_Mobile_UserId) {\n                        if(keyword.equals(user.getUid())) {\n                            if(keyword.equals(user.getName()) && keyword.equals(user.getMobile())) {\n                                if((value & ProtoConstants.DisableSearchMask.DisableSearchNameMask) > 0 && (value & ProtoConstants.DisableSearchMask.DisableSearchMobileMask) > 0) {\n                                    filter.add(user);\n                                    continue;\n                                }\n                            } else if(keyword.equals(user.getName())) {\n                                if((value & ProtoConstants.DisableSearchMask.DisableSearchNameMask) > 0) {\n                                    filter.add(user);\n                                    continue;\n                                }\n                            } else if(keyword.equals(user.getMobile())) {\n                                if((value & ProtoConstants.DisableSearchMask.DisableSearchMobileMask) > 0) {\n                                    filter.add(user);\n                                    continue;\n                                }\n                            } else {\n                                filter.add(user);\n                                continue;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        out.removeAll(filter);\n\n        return out;\n    }\n\n    List<WFCMessage.User> searchUserByDisplayName(String keyword, int userType, int page, List<WFCMessage.User> nameOrIdMatched) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n\n        ArrayList<WFCMessage.User> out = new ArrayList<>();\n\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select u._uid, u._name, u._display_name, u._portrait, u._mobile, u._gender, u._email, u._address, u._company, u._social, u._extra, u._dt, u._type \" +\n                \" from t_user u left join (select _uid, _value from t_user_setting where _scope = 27) s on u._uid = s._uid \" +\n                \" where u._display_name like ? ESCAPE '!' \";\n\n            if(userType == UserSearchUserType_ONLY_USER) {\n                sql += \" and u._type <> 2 \";\n                sql += \" and u._type <> 1 \";\n            } else if(userType == UserSearchUserType_ONLY_ROBOT) {\n                sql += \" and u._type = 1 \";\n            } else {\n                sql += \" and u._type <> 2 \";\n            }\n            sql += \" and u._deleted = 0 \";\n\n            if(nameOrIdMatched.size() == 1) {\n                sql += \" and u._uid <> ? and u._name <> ?\";\n            } else if(nameOrIdMatched.size() == 2) {\n                sql += \" and u._uid <> ? and u._uid <>? and u._name <> ? and u._name <>? \";\n            }\n            sql += \" and (s._value is null or (s._value <> 1 and s._value <> 3 and s._value <> 5 and s._value <> 7)) limit \";\n\n            if(page == 0) {\n                sql += (20 - nameOrIdMatched.size());\n            } else {\n                sql += 20;\n            }\n\n            if (page > 0) {\n                sql += \" offset \" + (page * 20 - nameOrIdMatched.size());\n            }\n\n            keyword = keyword\n                .replace(\"!\", \"!!\")\n                .replace(\"%\", \"!%\")\n                .replace(\"_\", \"!_\")\n                .replace(\"[\", \"![\");\n\n            statement = connection.prepareStatement(sql);\n            statement.setString(1, \"%\" + keyword + \"%\");\n            if(nameOrIdMatched.size() == 1) {\n                statement.setString(2, nameOrIdMatched.toArray(new WFCMessage.User[0])[0].getUid());\n                statement.setString(3, nameOrIdMatched.toArray(new WFCMessage.User[0])[0].getUid());\n            } else if(nameOrIdMatched.size() == 2) {\n                statement.setString(2, nameOrIdMatched.toArray(new WFCMessage.User[0])[0].getUid());\n                statement.setString(3, nameOrIdMatched.toArray(new WFCMessage.User[0])[1].getUid());\n                statement.setString(4, nameOrIdMatched.toArray(new WFCMessage.User[0])[0].getUid());\n                statement.setString(5, nameOrIdMatched.toArray(new WFCMessage.User[0])[1].getUid());\n            }\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                WFCMessage.User.Builder builder = WFCMessage.User.newBuilder();\n                int index = 1;\n\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setUid(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setName(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setDisplayName(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setPortrait(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setMobile(value);\n\n                int gender = rs.getInt(index++);\n                builder.setGender(gender);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setEmail(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setAddress(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setCompany(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setSocial(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setExtra(value);\n\n                long longValue = rs.getLong(index++);\n                builder.setUpdateDt(longValue);\n\n                int type = rs.getInt(index++);\n                builder.setType(type);\n\n                WFCMessage.User user = builder.build();\n\n                out.add(user);\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return out;\n    }\n\n    List<WFCMessage.User> searchUserFromDB(String keyword, int searchType, int userType, int page) {\n        List<WFCMessage.User> nameOrIdMatched = searchUserByNameMobileUserId(keyword, searchType, userType);\n        List<WFCMessage.User> out = new ArrayList<>();\n        if(page == 0) {\n            out.addAll(nameOrIdMatched);\n        }\n\n        if(searchType == SearchUserType_General || searchType == SearchUserType_Name_Mobile_DisplayName) {\n            List<WFCMessage.User> general = searchUserByDisplayName(keyword, userType, page, nameOrIdMatched);\n            general.removeAll(nameOrIdMatched);\n            out.addAll(general);\n        }\n        return out;\n    }\n\n    Integer getUserStatus(String userId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_status` from t_user_status where `_uid` = ?\";\n            statement = connection.prepareStatement(sql);\n\n            statement.setString(1, userId);\n            rs = statement.executeQuery();\n            if (rs.next()) {\n                return rs.getInt(1);\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return 0;\n    }\n\n    synchronized Collection<WFCMessage.GroupMember>  reloadGroupMemberFromDB(HazelcastInstance hzInstance, String groupId) {\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(MemoryMessagesStore.GROUP_MEMBERS);\n        if (groupMembers.get(groupId).size() > 0) {\n            return groupMembers.get(groupId);\n        }\n\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_mid`\" +\n                \", `_alias`\" +\n                \", `_type`\" +\n                \", `_dt`, `_create_dt`, `_extra` from t_group_member where _gid = ?\";\n            statement = connection.prepareStatement(sql);\n\n            statement.setString(1, groupId);\n            int index;\n\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                WFCMessage.GroupMember.Builder builder = WFCMessage.GroupMember.newBuilder();\n                index = 1;\n\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setMemberId(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setAlias(value);\n\n                int intvalue = rs.getInt(index++);\n                builder.setType(intvalue);\n\n\n                long longValue = rs.getLong(index++);\n                builder.setUpdateDt(longValue);\n\n                longValue = rs.getLong(index++);\n                builder.setCreateDt(longValue);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setExtra(value);\n\n                WFCMessage.GroupMember member = builder.build();\n                groupMembers.put(groupId, member);\n            }\n            return groupMembers.get(groupId);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return new ArrayList<>();\n    }\n\n    void reloadFriendsFromDB(HazelcastInstance hzInstance) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(MemoryMessagesStore.USER_FRIENDS);\n        if (friendsMap.size() > 0) {\n            return;\n        }\n\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_uid`, `_friend_uid`, `_alias`, `_state`, `_blacked`, `_dt`, `_extra` from t_friend\";\n            statement = connection.prepareStatement(sql);\n\n            int index;\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                FriendData builder = new FriendData();\n                index = 1;\n\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setUserId(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setFriendUid(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setAlias(value);\n\n                int intvalue = rs.getInt(index++);\n                builder.setState(intvalue);\n\n                intvalue = rs.getInt(index++);\n                builder.setBlacked(intvalue);\n\n                long longvalue = rs.getLong(index++);\n                builder.setTimestamp(longvalue);\n\n                builder.setExtra(rs.getString(index++));\n\n                friendsMap.put(builder.getUserId(), builder);\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n    }\n\n    void reloadFriendRequestsFromDB(HazelcastInstance hzInstance) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        MultiMap<String, WFCMessage.FriendRequest> requestMap = hzInstance.getMultiMap(MemoryMessagesStore.USER_FRIENDS_REQUEST);\n        if (requestMap.size() > 0) {\n            return;\n        }\n\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_uid`, `_friend_uid`, `_reason`, `_status`, `_dt`, `_from_read_status`, `_to_read_status`, `_extra` from t_friend_request\";\n            statement = connection.prepareStatement(sql);\n\n            int index;\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                WFCMessage.FriendRequest.Builder builder = WFCMessage.FriendRequest.newBuilder();\n                index = 1;\n\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setFromUid(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setToUid(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setReason(value);\n\n                int intvalue = rs.getInt(index++);\n                builder.setStatus(intvalue);\n\n                long longvalue = rs.getLong(index++);\n                builder.setUpdateDt(longvalue);\n\n                intvalue = rs.getInt(index++);\n                builder.setFromReadStatus(intvalue > 0);\n\n                intvalue = rs.getInt(index++);\n                builder.setToReadStatus(intvalue > 0);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setExtra(value);\n\n                WFCMessage.FriendRequest request = builder.build();\n                requestMap.put(request.getFromUid(), request);\n                requestMap.put(request.getToUid(), request);\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n    }\n\n\n    void persistMessage(final WFCMessage.Message message, boolean update) {\n        if(message.getContent().getPersistFlag() == Transparent) {\n            return;\n        }\n\n        mScheduler.execute(()-> {\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String table = MessageShardingUtil.getMessageTable(message.getMessageId());\n                String sql;\n                if (disableRemoteMessageSearch) {\n                    sql = \"insert into \" + table +\n                        \" (`_mid`, `_from`, `_type`, `_target`, `_line`, `_data`, `_dt`, `_content_type`, `_to`) values(?, ?, ?, ?, ?, ?, ?, ?, ?)\" +\n                        \" ON DUPLICATE KEY UPDATE \" +\n                        \"`_data` = ?,\" +\n                        \"`_dt` = ?,\" +\n                        \"`_content_type` = ?\";\n                } else {\n                    sql = \"insert into \" + table +\n                        \" (`_mid`, `_from`, `_type`, `_target`, `_line`, `_data`, `_searchable_key`, `_dt`, `_content_type`, `_to`) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\" +\n                        \" ON DUPLICATE KEY UPDATE \" +\n                        \"`_data` = ?,\" +\n                        \"`_searchable_key` = ?,\" +\n                        \"`_dt` = ?,\" +\n                        \"`_content_type` = ?\";\n                }\n\n                String searchableContent = message.getContent().getSearchableContent() == null ? \"\" : message.getContent().getSearchableContent();\n\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setLong(index++, message.getMessageId());\n                statement.setString(index++, message.getFromUser());\n                statement.setInt(index++, message.getConversation().getType());\n                statement.setString(index++, message.getConversation().getTarget());\n                statement.setInt(index++, message.getConversation().getLine());\n                Blob blob = connection.createBlob();\n                blob.setBytes(1, encryptMessageContent(message.getContent().toByteArray(), false));\n                statement.setBlob(index++, blob);\n                if (!disableRemoteMessageSearch) {\n                    statement.setString(index++, searchableContent);\n                }\n                statement.setTimestamp(index++, new Timestamp(message.getServerTimestamp()));\n                statement.setInt(index++, message.getContent().getType());\n                String to = message.getToUser();\n                if (StringUtil.isNullOrEmpty(message.getToUser())) {\n                    if (message.getToList().size() > 0) {\n                        to = message.getToList().get(0);\n                    }\n                }\n                statement.setString(index++, to);\n\n                statement.setBlob(index++, blob);\n                if (!disableRemoteMessageSearch) {\n                    statement.setString(index++, searchableContent);\n                }\n                statement.setTimestamp(index++, new Timestamp(message.getServerTimestamp()));\n                statement.setInt(index++, message.getContent().getType());\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    byte[] encryptMessageContent(byte[] in, boolean force) {\n        if(in != null && (encryptMessage || force)) {\n            for (int i = 0; i < in.length; i++) {\n                in[i] ^= 0xBD;\n            }\n        }\n        return in;\n    }\n\n    void persistSensitiveMessage(final WFCMessage.Message message) {\n        if(message.getContent().getPersistFlag() == Transparent) {\n            return;\n        }\n\n        mScheduler.execute(()-> {\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"insert into \" + \"t_sensitive_messages\" +\n                    \" (`_mid`, `_from`, `_type`, `_target`, `_line`, `_data`, `_searchable_key`, `_dt`, `_content_type`) values(?, ?, ?, ?, ?, ?, ?, ?, ?)\" +\n                    \" ON DUPLICATE KEY UPDATE \" +\n                    \"`_data` = ?,\" +\n                    \"`_searchable_key` = ?,\" +\n                    \"`_dt` = ?,\" +\n                    \"`_content_type` = ?\";\n\n                String searchableContent = message.getContent().getSearchableContent() == null ? \"\" : message.getContent().getSearchableContent();\n\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setLong(index++, message.getMessageId());\n                statement.setString(index++, message.getFromUser());\n                statement.setInt(index++, message.getConversation().getType());\n                statement.setString(index++, message.getConversation().getTarget());\n                statement.setInt(index++, message.getConversation().getLine());\n                Blob blob = connection.createBlob();\n                blob.setBytes(1, encryptMessageContent(message.getContent().toByteArray(), false));\n                statement.setBlob(index++, blob);\n                statement.setString(index++, searchableContent);\n                statement.setTimestamp(index++, new Timestamp(message.getServerTimestamp()));\n                statement.setInt(index++, message.getContent().getType());\n\n                statement.setBlob(index++, blob);\n                statement.setString(index++, searchableContent);\n                statement.setTimestamp(index++, new Timestamp(message.getServerTimestamp()));\n                statement.setInt(index++, message.getContent().getType());\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    Map<Long, MessageBundle> getMessages(Collection<Long> keys) {\n        Map<String, List<Long>> messageTableMap = new HashMap<>();\n        for (Long key : keys) {\n            String messageTableId = MessageShardingUtil.getMessageTable(key);\n\n            messageTableMap.computeIfAbsent(messageTableId, new Function<String, List<Long>>() {\n                @Override\n                public List<Long> apply(String s) {\n                    return new ArrayList<>();\n                }\n            });\n            messageTableMap.get(messageTableId).add(key);\n        }\n\n        Map<Long, MessageBundle> out = null;\n        Connection connection = null;\n        try {\n            connection = DBUtil.getConnection();\n            out = new HashMap<>();\n            for (Map.Entry<String, List<Long>> entry : messageTableMap.entrySet()) {\n                String sql = \"select `_mid`, `_from`, `_type`, `_target`, `_line`, `_data`, `_dt` from \" + entry.getKey() +\" where _mid in (\";\n                for (int i = 0; i < entry.getValue().size(); i++) {\n                    sql += entry.getValue().get(i);\n                    if (i != entry.getValue().size() - 1) {\n                        sql += \",\";\n                    }\n                }\n                sql += \")\";\n\n                ResultSet resultSet = null;\n                try {\n                    PreparedStatement statement = connection.prepareStatement(sql);\n                    resultSet = statement.executeQuery();\n\n                    while (resultSet.next()) {\n                        WFCMessage.Message.Builder builder = WFCMessage.Message.newBuilder();\n                        int index = 1;\n                        builder.setMessageId(resultSet.getLong(index++));\n                        builder.setFromUser(resultSet.getString(index++));\n                        WFCMessage.Conversation.Builder cb = WFCMessage.Conversation.newBuilder();\n                        cb.setType(resultSet.getInt(index++));\n                        cb.setTarget(resultSet.getString(index++));\n                        cb.setLine(resultSet.getInt(index++));\n                        builder.setConversation(cb.build());\n                        Blob blob = resultSet.getBlob(index++);\n\n                        WFCMessage.MessageContent messageContent = WFCMessage.MessageContent.parseFrom(encryptMessageContent(toByteArray(blob.getBinaryStream()), false));\n                        builder.setContent(messageContent);\n                        builder.setServerTimestamp(resultSet.getTimestamp(index++).getTime());\n                        WFCMessage.Message message = builder.build();\n                        out.put(message.getMessageId(),new MessageBundle(message.getMessageId(), message.getFromUser(), null, message));\n                    }\n                } catch (SQLException e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, RDBS_Exception);\n                } catch (IOException e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, RDBS_Exception);\n                } finally {\n                    try {\n                        if (resultSet!=null) {\n                            resultSet.close();\n                        }\n                    } catch (SQLException e) {\n                        e.printStackTrace();\n                        Utility.printExecption(LOG, e, RDBS_Exception);\n                    }\n                }\n            }\n\n        } catch (SQLException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, null);\n        }\n\n        return out;\n    }\n\n    public byte[] toByteArray(InputStream input) throws IOException {\n        ByteArrayOutputStream output = new ByteArrayOutputStream();\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        return output.toByteArray();\n    }\n\n    MessageBundle getMessage(long messageId) {\n        String sql = \"select  `_from`, `_type`, `_target`, `_line`, `_data`, `_dt` from \" + MessageShardingUtil.getMessageTable(messageId) +\" where _mid = ? order by `_dt` DESC limit 1\";\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet resultSet = null;\n        try {\n            connection = DBUtil.getConnection();\n            statement = connection.prepareStatement(sql);\n            statement.setLong(1, messageId);\n            resultSet = statement.executeQuery();\n            if (resultSet.next()) {\n                WFCMessage.Message.Builder builder = WFCMessage.Message.newBuilder();\n                builder.setMessageId(messageId);\n                int index = 1;\n                builder.setFromUser(resultSet.getString(index++));\n                WFCMessage.Conversation.Builder cb = WFCMessage.Conversation.newBuilder();\n                cb.setType(resultSet.getInt(index++));\n                cb.setTarget(resultSet.getString(index++));\n                cb.setLine(resultSet.getInt(index++));\n                builder.setConversation(cb.build());\n                Blob blob = resultSet.getBlob(index++);\n\n                WFCMessage.MessageContent messageContent = WFCMessage.MessageContent.parseFrom(encryptMessageContent(toByteArray(blob.getBinaryStream()), false));\n                builder.setContent(messageContent);\n                builder.setServerTimestamp(resultSet.getTimestamp(index++).getTime());\n                WFCMessage.Message message = builder.build();\n                return new MessageBundle(messageId, message.getFromUser(), null, message);\n            }\n        } catch (SQLException | IOException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, resultSet);\n        }\n        return null;\n    }\n\n    void deleteMessage(long messageId) {\n        String sql = \"delete from \" + MessageShardingUtil.getMessageTable(messageId) + \" where _mid = ?\";\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            statement = connection.prepareStatement(sql);\n            statement.setLong(1, messageId);\n\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n        } catch (SQLException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    List<WFCMessage.Message> loadRemoteMessages(String user, WFCMessage.Conversation conversation, long beforeUid, int count, Collection<Integer> contentTypes, String channelOwner) {\n        List<WFCMessage.Message> messages = new ArrayList<>();\n        long[] before = new long[1];\n        before[0] = beforeUid;\n        boolean hasMore = loadRemoteMessagesFromTable(user, conversation, before, count, MessageShardingUtil.getMessageTable(beforeUid), messages, contentTypes, channelOwner);\n        while (messages.size() < count && hasMore) {\n            hasMore = loadRemoteMessagesFromTable(user, conversation, before, count - messages.size(), MessageShardingUtil.getMessageTable(beforeUid), messages, contentTypes, channelOwner);\n        }\n\n        int month = 0;\n        while (messages.size() < count && !DBUtil.IsEmbedDB && month++ < 24) {\n            String nexTable = MessageShardingUtil.getMessageTable(beforeUid, -month);\n\n            int size = messages.size();\n            hasMore = true;\n            while (size == messages.size() && hasMore) {\n                hasMore = loadRemoteMessagesFromTable(user, conversation, before, count - messages.size(), nexTable, messages, contentTypes, channelOwner);\n            }\n\n            if (size < messages.size()) {\n                break;\n            }\n        }\n\n        return messages;\n    }\n\n    boolean loadRemoteMessagesFromTable(String user, WFCMessage.Conversation conversation, long[] before, int count, String table, List<WFCMessage.Message> messages, Collection<Integer> contentTypes, String channelOwner) {\n        long beforeUid = before[0];\n        String sql = \"select `_mid`, `_from`, `_type`, `_target`, `_line`, `_data`, `_dt`, `_to` from \" + table +\" where\";\n        if (conversation.getType() == ProtoConstants.ConversationType.ConversationType_Private) {\n            sql += \" _type = ? and _line = ? and _mid < ? and ((_target = ?  and _from = ?) or (_target = ?  and _from = ?)) and (_to = '' or _to = ?)\";\n        } else if (conversation.getType() == ProtoConstants.ConversationType.ConversationType_Channel && !user.equals(channelOwner)) {\n            sql += \" _type = ? and _line = ? and _mid < ? and _target = ? and ((_from = ? and (_to = '' or _to = ?)) or (_from = ?))\";\n        } else {\n            sql += \" _type = ? and _line = ? and _mid < ? and _target = ?\";\n        }\n\n        if(contentTypes != null && !contentTypes.isEmpty()) {\n            sql += \" and _content_type in (\";\n            boolean first = true;\n            for (int i:contentTypes) {\n                if(first) {\n                    first = false;\n                } else {\n                    sql += \",\";\n                }\n                sql += i;\n            }\n            sql += \")\";\n        }\n\n        sql += \" order by `_mid` DESC limit ?\";\n\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet resultSet = null;\n        try {\n            connection = DBUtil.getConnection();\n            statement = connection.prepareStatement(sql);\n            int index = 1;\n            statement.setInt(index++, conversation.getType());\n            statement.setInt(index++, conversation.getLine());\n            statement.setLong(index++, beforeUid);\n            statement.setString(index++, conversation.getTarget());\n            if (conversation.getType() == ProtoConstants.ConversationType.ConversationType_Private) {\n                statement.setString(index++, user);\n                statement.setString(index++, user);\n                statement.setString(index++, conversation.getTarget());\n                statement.setString(index++, user);\n            } else if (conversation.getType() == ProtoConstants.ConversationType.ConversationType_Channel && !user.equals(channelOwner)) {\n                statement.setString(index++, channelOwner);\n                statement.setString(index++, user);\n                statement.setString(index++, user);\n            }\n\n            statement.setInt(index++, count);\n            resultSet = statement.executeQuery();\n            while (resultSet.next()) {\n                count--;\n                WFCMessage.Message.Builder builder = WFCMessage.Message.newBuilder();\n                index = 1;\n                builder.setMessageId(resultSet.getLong(index++));\n                before[0] = builder.getMessageId();\n\n                builder.setFromUser(resultSet.getString(index++));\n                WFCMessage.Conversation.Builder cb = WFCMessage.Conversation.newBuilder();\n                cb.setType(resultSet.getInt(index++));\n                cb.setTarget(resultSet.getString(index++));\n                cb.setLine(resultSet.getInt(index++));\n                builder.setConversation(cb.build());\n                Blob blob = resultSet.getBlob(index++);\n\n                WFCMessage.MessageContent messageContent = WFCMessage.MessageContent.parseFrom(encryptMessageContent(toByteArray(blob.getBinaryStream()), false));\n\n                builder.setContent(messageContent);\n\n                builder.setServerTimestamp(resultSet.getTimestamp(index++).getTime());\n                String to = resultSet.getString(index++);\n                if (!StringUtil.isNullOrEmpty(to)) {\n                    if (to.equals(user) || builder.getFromUser().equals(user)) {\n                        builder.setToUser(to);\n                    } else {\n                        continue;\n                    }\n                }\n                WFCMessage.Message message = builder.build();\n                boolean expired = false;\n                if (message.getContent().getExpireDuration() > 0) {\n                    if (System.currentTimeMillis() > message.getServerTimestamp() + message.getContent().getExpireDuration()*1000) {\n                        expired = true;\n                    }\n                }\n\n                if (!expired) {\n                    boolean duplicated = false;\n                    for (WFCMessage.Message msg : messages) {\n                        if(message.getMessageId() == msg.getMessageId()) {\n                            duplicated = true;\n                            break;\n                        }\n                    }\n                    if(!duplicated) {\n                        messages.add(message);\n                    }\n                }\n            }\n\n            if (count == 0) {\n                return true;\n            }\n        } catch (SQLException | IOException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, resultSet);\n        }\n        return false;\n    }\n\n    void persistUserMessage(final String userId, final  String sender, final long messageId, final long messageSeq, int type, String target, int line, boolean directing, final int messageContentType) {\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n\n                String sql = \"insert into \" + getUserMessageTable(userId) + \" (`_mid`, `_uid`, `_seq`, `_type`, `_target`, `_line`, `_directing`, `_cont_type`) values(?, ?, ?, ?, ?, ?, ?, ?)\";\n\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setLong(index++, messageId);\n                statement.setString(index++, userId);\n                statement.setLong(index++, messageSeq);\n                statement.setInt(index++, type);\n                statement.setString(index++, getPrivateChatUserMessageTarget(type, target, sender));\n                statement.setInt(index++, line);\n                statement.setInt(index++, directing ? 1 :0);\n                statement.setInt(index++, messageContentType);\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    String getPrivateChatUserMessageTarget(int conversationType, String target, String userId) {\n        if(conversationType == ProtoConstants.ConversationType.ConversationType_Private) {\n            return target.compareTo(userId) > 0 ? (userId + \"|\" + target) : (target + \"|\" + userId);\n        } else {\n            return target;\n        }\n    }\n\n    void clearUserMessage(final String userId) {\n        mScheduler.execute(()->{\n            String tableName = getUserMessageTable(userId);\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n\n                String sql = \"delete from \" + tableName + \" where _uid = ?\";\n                statement = connection.prepareStatement(sql);\n                statement.setString(1, userId);\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n\n                try {\n                    if (statement!=null) {\n                        statement.close();\n                    }\n                    statement = null;\n                } catch (SQLException e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, RDBS_Exception);\n                }\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n\n    }\n\n    void removeFavGroup(final String groupId, final List<String> memberIds) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n\n            StringBuilder sb = new StringBuilder(\"update t_user_setting set _value = ?, _dt = ? where _uid in (\");\n            for (int i = 0; i < memberIds.size(); i++) {\n                sb.append(\"?\");\n                if (i != memberIds.size() - 1) {\n                    sb.append(\",\");\n                }\n            }\n            sb.append(\")\");\n\n            sb.append(\" and _scope in (5,6,26) and _key = ?\");\n\n            statement = connection.prepareStatement(sb.toString());\n            int index = 1;\n            statement.setString(index++, \"0\");\n            statement.setLong(index++, System.currentTimeMillis());\n            for (int i = 0; i < memberIds.size(); i++) {\n                statement.setString(index++, memberIds.get(i));\n            }\n            statement.setString(index++, groupId);\n\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    void persistUserSetting(final String userId, WFCMessage.UserSettingEntry entry) {\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n\n                String sql = \"insert into t_user_setting (`_uid`\" +\n                    \", `_scope`\" +\n                    \", `_key`\" +\n                    \", `_value`\" +\n                    \", `_dt`) values(?, ?, ?, ?, ?)\" +\n                    \" ON DUPLICATE KEY UPDATE \" +\n                    \"`_value` = ?,\" +\n                    \"`_dt` = ?\";\n\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setString(index++, userId);\n                statement.setInt(index++, entry.getScope());\n                statement.setString(index++, entry.getKey());\n                statement.setString(index++, entry.getValue());\n                statement.setLong(index++, entry.getUpdateDt());\n                statement.setString(index++, entry.getValue());\n                statement.setLong(index++, entry.getUpdateDt());\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    void clearUserSetting(final String userId) {\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n\n                String sql = \"delete from t_user_setting where `_uid` = ?\";\n\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setString(index++, userId);\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    List<WFCMessage.UserSettingEntry> getPersistUserSetting(final String userId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select \" +\n                \"`_scope`\" +\n                \", `_key`\" +\n                \", `_value`\" +\n                \", `_dt`\" +\n                \" from t_user_setting where `_uid` = ?\";\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setString(index++, userId);\n\n\n            rs = statement.executeQuery();\n            List<WFCMessage.UserSettingEntry> out = new ArrayList<>();\n            while (rs.next()) {\n                WFCMessage.UserSettingEntry.Builder builder = WFCMessage.UserSettingEntry.newBuilder();\n\n                index = 1;\n                int intvalue = rs.getInt(index++);\n                builder.setScope(intvalue);\n\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setKey(value);\n\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setValue(value);\n\n                long longValue = rs.getLong(index++);\n                builder.setUpdateDt(longValue);\n\n                out.add(builder.build());\n            }\n            if (out.isEmpty()) {\n                WFCMessage.UserSettingEntry.Builder builder = WFCMessage.UserSettingEntry.newBuilder().setScope(999).setKey(\"\").setValue(\"\").setUpdateDt(0);\n                out.add(builder.build());\n            }\n            return out;\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n\n    void removeGroupUserSettings(String groupId, List<String> users) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n\n            StringBuilder sb = new StringBuilder(\"delete from t_user_setting where _scope in (1,3,5,6,7,19) and _uid in (\");\n            for (int i = 0; i < users.size(); i++) {\n                sb.append(\"?\");\n                if (i != users.size() - 1) {\n                    sb.append(\",\");\n                }\n            }\n            sb.append(\") and _key like ?\");\n\n            statement = connection.prepareStatement(sb.toString());\n            int index = 1;\n            for (String userId:users) {\n                statement.setString(index++, userId);\n            }\n            statement.setString(index++, \"1-_-\" + groupId);\n\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    void persistGroupInfo(final WFCMessage.GroupInfo groupInfo) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"insert into t_group (`_gid`\" +\n                \", `_name`\" +\n                \", `_portrait`\" +\n                \", `_owner`\" +\n                \", `_type`\" +\n                \", `_extra`\" +\n                \", `_dt`\" +\n                \", `_member_count`\" +\n                \", `_mute`\" +\n                \", `_join_type`\" +\n                \", `_private_chat`\" +\n                \", `_searchable`\" +\n                \", `_deleted`\" +\n                \", `_member_dt`) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\" +\n                \" ON DUPLICATE KEY UPDATE \" +\n                \"`_name` = ?,\" +\n                \"`_portrait` = ?,\" +\n                \"`_owner` = ?,\" +\n                \"`_type` = ?,\" +\n                \"`_extra` = ?,\" +\n                \"`_dt` = ?,\" +\n                \"`_mute` = ?\" +\n                \", `_join_type` = ?\" +\n                \", `_private_chat` = ?\" +\n                \", `_searchable` = ?\" +\n                \", `_deleted` = ?\" +\n                \", `_member_dt` = ?\";\n\n\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setString(index++, groupInfo.getTargetId());\n            statement.setString(index++, groupInfo.getName());\n            statement.setString(index++, groupInfo.getPortrait());\n            statement.setString(index++, groupInfo.getOwner());\n            statement.setInt(index++, groupInfo.getType());\n            statement.setString(index++, groupInfo.getExtra());\n            statement.setLong(index++, groupInfo.getUpdateDt() == 0 ? System.currentTimeMillis() : groupInfo.getUpdateDt());\n            statement.setInt(index++, groupInfo.getMemberCount());\n            statement.setInt(index++, groupInfo.getMute());\n            statement.setInt(index++, groupInfo.getJoinType());\n            statement.setInt(index++, groupInfo.getPrivateChat());\n            statement.setInt(index++, groupInfo.getSearchable());\n            statement.setInt(index++, groupInfo.getDeleted());\n            statement.setLong(index++, groupInfo.getMemberUpdateDt() == 0 ? System.currentTimeMillis() : groupInfo.getUpdateDt());\n\n            statement.setString(index++, groupInfo.getName());\n            statement.setString(index++, groupInfo.getPortrait());\n            statement.setString(index++, groupInfo.getOwner());\n            statement.setInt(index++, groupInfo.getType());\n            statement.setString(index++, groupInfo.getExtra());\n            statement.setLong(index++, groupInfo.getUpdateDt() == 0 ? System.currentTimeMillis() : groupInfo.getUpdateDt());\n            statement.setInt(index++, groupInfo.getMute());\n            statement.setInt(index++, groupInfo.getJoinType());\n            statement.setInt(index++, groupInfo.getPrivateChat());\n            statement.setInt(index++, groupInfo.getSearchable());\n            statement.setInt(index++, groupInfo.getDeleted());\n            statement.setLong(index++, groupInfo.getMemberUpdateDt() == 0 ? System.currentTimeMillis() : groupInfo.getUpdateDt());\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    List<MemorySessionStore.Session> getUserActivedSessions(String uid) {\n        String sql = \"select  `_cid`, `_package_name`,`_token`,`_voip_token`,`_secret`,`_db_secret`,`_platform`,`_push_type`,`_device_name`,`_device_version`,`_phone_name`,`_language`,`_carrier_name`, `_dt` from t_user_session where `_uid` = ? and `_deleted` = 0\";\n        Connection connection = null;\n        PreparedStatement statement = null;\n        List<MemorySessionStore.Session> result = new ArrayList<>();\n        ResultSet resultSet = null;\n        try {\n            connection = DBUtil.getConnection();\n            statement = connection.prepareStatement(sql);\n            statement.setString(1, uid);\n\n            resultSet = statement.executeQuery();\n            while (resultSet.next()) {\n                int index = 1;\n                String cid = resultSet.getString(index++);\n\n                ClientSession clientSession = new ClientSession(cid, Server.getServer().getStore().sessionsStore());\n                MemorySessionStore.Session session = new MemorySessionStore.Session(uid, cid, clientSession);\n\n                session.setAppName(resultSet.getString(index++));\n                session.setDeviceToken(resultSet.getString(index++));\n                session.setVoipDeviceToken(resultSet.getString(index++));\n                session.setSecret(resultSet.getString(index++));\n                session.setDbSecret(resultSet.getString(index++));\n                session.setPlatform(resultSet.getInt(index++));\n                session.setPushType(resultSet.getInt(index++));\n\n                session.setDeviceName(resultSet.getString(index++));\n                session.setDeviceVersion(resultSet.getString(index++));\n                session.setPhoneName(resultSet.getString(index++));\n                session.setLanguage(resultSet.getString(index++));\n                session.setCarrierName(resultSet.getString(index++));\n                session.setUpdateDt(resultSet.getLong(index++));\n                result.add(session);\n            }\n        } catch (SQLException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, resultSet);\n        }\n        return result;\n    }\n\n    void clearUserSessions(String uid) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"delete from t_user_session where `_uid`=?\";\n            statement = connection.prepareStatement(sql);\n            int index = 1;\n            statement.setString(index++, uid);\n\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    MemorySessionStore.Session getSession(String uid, String clientId, ClientSession clientSession) {\n        String sql = \"select  `_package_name`,`_token`,`_voip_token`,`_secret`,`_db_secret`,`_platform`,`_push_type`,`_device_name`,`_device_version`,`_phone_name`,`_language`,`_carrier_name`, `_dt`, `_deleted` from t_user_session where `_uid` = ? and `_cid` = ? limit 1\";\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet resultSet = null;\n        try {\n            connection = DBUtil.getConnection();\n            statement = connection.prepareStatement(sql);\n            statement.setString(1, uid);\n            statement.setString(2, clientId);\n            resultSet = statement.executeQuery();\n            if (resultSet.next()) {\n                MemorySessionStore.Session session = new MemorySessionStore.Session(uid, clientId, clientSession);\n\n                int index = 1;\n                session.setAppName(resultSet.getString(index++));\n                session.setDeviceToken(resultSet.getString(index++));\n                session.setVoipDeviceToken(resultSet.getString(index++));\n                session.setSecret(resultSet.getString(index++));\n                session.setDbSecret(resultSet.getString(index++));\n                session.setPlatform(resultSet.getInt(index++));\n                session.setPushType(resultSet.getInt(index++));\n\n                session.setDeviceName(resultSet.getString(index++));\n                session.setDeviceVersion(resultSet.getString(index++));\n                session.setPhoneName(resultSet.getString(index++));\n                session.setLanguage(resultSet.getString(index++));\n                session.setCarrierName(resultSet.getString(index++));\n                session.setUpdateDt(resultSet.getLong(index++));\n                session.setDeleted(resultSet.getInt(index));\n                return session;\n            }\n        } catch (SQLException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, resultSet);\n        }\n        return null;\n    }\n\n    void clearOtherSessionToken(String cid, String token, int pushType, boolean voipToken) {\n        if (voipToken) {\n            return;\n        }\n\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n\n            String sql = \"update t_user_session set `_token` = ?, `_dt` = ? where `_token` = ? and `_push_type` = ? and `_cid` <> ?\";\n\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setString(index++, \"\");\n            statement.setLong(index++, System.currentTimeMillis());\n            statement.setString(index++, token);\n            statement.setInt(index++, pushType);\n            statement.setString(index++, cid);\n\n            int c = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", c);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n\n    void updateSessionToken(String uid, String cid, String token, int pushType, boolean voipToken) {\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n\n            clearOtherSessionToken(cid, token, pushType, voipToken);\n            try {\n                connection = DBUtil.getConnection();\n\n                String sql ;\n\n                if (voipToken) {\n                    sql = \"update t_user_session set `_voip_token` = ?, `_dt` = ? where `_uid` = ? and `_cid` = ?\";\n                } else {\n                    sql = \"update t_user_session set `_token` = ?, `_push_type` = ?, `_dt` = ? where `_uid` = ? and `_cid` = ?\";\n                }\n                statement = connection.prepareStatement(sql);\n\n                int index = 1;\n                statement.setString(index++, token);\n                if (!voipToken) {\n                    statement.setInt(index++, pushType);\n                }\n                statement.setLong(index++, System.currentTimeMillis());\n                statement.setString(index++, uid);\n                statement.setString(index++, cid);\n\n                int c = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", c);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    void updateSessionDeleted(String uid, String cid, int deleted) {\n            Connection connection = null;\n            PreparedStatement statement = null;\n\n            try {\n                connection = DBUtil.getConnection();\n\n                String sql = \"update t_user_session set `_deleted` = ? where `_uid` = ? and `_cid` = ?\";\n\n                statement = connection.prepareStatement(sql);\n\n                int index = 1;\n                statement.setInt(index++, deleted);\n                statement.setString(index++, uid);\n                statement.setString(index++, cid);\n\n                int c = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", c);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n    }\n\n    void updateSessionPlatform(String uid, String cid, int platform) {\n            Connection connection = null;\n            PreparedStatement statement = null;\n\n            try {\n                connection = DBUtil.getConnection();\n\n                String sql = \"update t_user_session set `_platform` = ? where `_uid` = ? and `_cid` = ?\";\n\n                statement = connection.prepareStatement(sql);\n\n                int index = 1;\n                statement.setInt(index++, platform);\n                statement.setString(index++, uid);\n                statement.setString(index++, cid);\n\n                int c = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", c);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n    }\n\n    private boolean strEqual(String left, String right) {\n        if (left == right)\n            return true;\n        if (left == null)\n            return false;\n        return left.equals(right);\n    }\n\n    void updateSession(String uid, String cid, MemorySessionStore.Session session, WFCMessage.RouteRequest request) {\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n\n                String sql = \"update t_user_session set\";\n\n\n                if (!strEqual(session.getAppName(), request.getApp())) {\n                    sql += \" `_package_name` = ?,\";\n                }\n                if (!strEqual(session.getDeviceName(), request.getDeviceName())) {\n                    sql += \" `_device_name` = ?,\";\n                }\n                if (!strEqual(session.getDeviceVersion(), request.getDeviceVersion())) {\n                    sql += \" `_device_version` = ?,\";\n                }\n                if (!strEqual(session.getPhoneName(), request.getPhoneName())) {\n                    sql += \" `_phone_name` = ?,\";\n                }\n                if (!strEqual(session.getLanguage(), request.getLanguage())) {\n                    sql += \" `_language` = ?,\";\n                }\n                if (!strEqual(session.getCarrierName(), request.getCarrierName())) {\n                    sql += \" `_carrier_name` = ?,\";\n                }\n\n                sql += \" `_dt` = ?\";\n\n                sql += \" where `_uid` = ? and `_cid` = ?\";\n\n                statement = connection.prepareStatement(sql);\n\n                int index = 1;\n\n                if (!strEqual(session.getAppName(), request.getApp())) {\n                    statement.setString(index++, request.getApp());\n                }\n                if (!strEqual(session.getDeviceName(), request.getDeviceName())) {\n                    statement.setString(index++, request.getDeviceName());\n                }\n                if (!strEqual(session.getDeviceVersion(), request.getDeviceVersion())) {\n                    statement.setString(index++, request.getDeviceVersion());\n                }\n                if (!strEqual(session.getPhoneName(), request.getPhoneName())) {\n                    statement.setString(index++, request.getPhoneName());\n                }\n                if (!strEqual(session.getLanguage(), request.getLanguage())) {\n                    statement.setString(index++, request.getLanguage());\n                }\n                if (!strEqual(session.getCarrierName(), request.getCarrierName())) {\n                    statement.setString(index++, request.getCarrierName());\n                }\n\n                statement.setLong(index++, System.currentTimeMillis());\n                statement.setString(index++, uid);\n                statement.setString(index++, cid);\n\n                int c = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", c);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    void updateSessionIp(String uid, String cid, String ip) {\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"update t_user_session set _ip = ?  where `_uid` = ? and `_cid` = ?\";\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setString(index++, ip);\n                statement.setString(index++, uid);\n                statement.setString(index++, cid);\n\n                int c = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", c);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    void clearMultiEndpoint(String uid, String clientId, int platform) {\n        LOG.info(\"clearMultiEndpoint {}, {}\", uid, clientId);\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql;\n            if (platform == ProtoConstants.Platform.Platform_Windows || platform == ProtoConstants.Platform.Platform_OSX || platform == ProtoConstants.Platform.Platform_LINUX || platform == ProtoConstants.Platform.Platform_HarmonyPC) {\n                sql = \"update t_user_session set `_deleted` = ?, `_token` = ?, `_voip_token` = ?, `_dt` = ?  where `_uid`=? and (`_platform` = ? or `_platform` = ? or `_platform` = ? or `_platform` = ?)  and `_cid` <> ? and `_deleted` = 0\";\n            } else if(platform == ProtoConstants.Platform.Platform_iOS || platform == ProtoConstants.Platform.Platform_Android || platform == ProtoConstants.Platform.Platform_Harmony) {\n                sql = \"update t_user_session set `_deleted` = ?, `_token` = ?, `_voip_token` = ?, `_dt` = ?  where `_uid`=? and (`_platform` = ? or `_platform` = ? or `_platform` = ?)  and `_cid` <> ? and `_deleted` = 0\";\n            } else if(platform == ProtoConstants.Platform.Platform_iPad || platform == ProtoConstants.Platform.Platform_APad || platform == ProtoConstants.Platform.Platform_HarmonyPad) {\n                sql = \"update t_user_session set `_deleted` = ?, `_token` = ?, `_voip_token` = ?, `_dt` = ?  where `_uid`=? and (`_platform` = ? or `_platform` = ? or `_platform` = ?)  and `_cid` <> ? and `_deleted` = 0\";\n            } else if(platform == ProtoConstants.Platform.Platform_AndroidWearable || platform == ProtoConstants.Platform.Platform_HarmonyWearable) {\n                sql = \"update t_user_session set `_deleted` = ?, `_token` = ?, `_voip_token` = ?, `_dt` = ?  where `_uid`=? and (`_platform` = ? or `_platform` = ?)  and `_cid` <> ? and `_deleted` = 0\";\n            } else if(platform == ProtoConstants.Platform.Platform_AndroidTV || platform == ProtoConstants.Platform.Platform_AppleTV || platform == ProtoConstants.Platform.Platform_HarmonyTV) {\n                sql = \"update t_user_session set `_deleted` = ?, `_token` = ?, `_voip_token` = ?, `_dt` = ?  where `_uid`=? and (`_platform` = ? or `_platform` = ? or `_platform` = ?)  and `_cid` <> ? and `_deleted` = 0\";\n            } else {\n                sql = \"update t_user_session set `_deleted` = ?, `_token` = ?, `_voip_token` = ?, `_dt` = ?  where `_uid`=? and `_platform` = ? and `_cid` <> ? and `_deleted` = 0\";\n            }\n\n            statement = connection.prepareStatement(sql);\n            int index = 1;\n\n            statement.setInt(index++, 1);\n            statement.setString(index++, \"\");\n            statement.setString(index++, \"\");\n            statement.setLong(index++, System.currentTimeMillis());\n\n            statement.setString(index++, uid);\n\n            if (platform == ProtoConstants.Platform.Platform_Windows || platform == ProtoConstants.Platform.Platform_OSX || platform == ProtoConstants.Platform.Platform_LINUX || platform == ProtoConstants.Platform.Platform_HarmonyPC) {\n                statement.setInt(index++, ProtoConstants.Platform.Platform_Windows);\n                statement.setInt(index++, ProtoConstants.Platform.Platform_OSX);\n                statement.setInt(index++, ProtoConstants.Platform.Platform_LINUX);\n                statement.setInt(index++, ProtoConstants.Platform.Platform_HarmonyPC);\n            } else if(platform == ProtoConstants.Platform.Platform_iOS || platform == ProtoConstants.Platform.Platform_Android || platform == ProtoConstants.Platform.Platform_Harmony) {\n                statement.setInt(index++, ProtoConstants.Platform.Platform_iOS);\n                statement.setInt(index++, ProtoConstants.Platform.Platform_Android);\n                statement.setInt(index++, ProtoConstants.Platform.Platform_Harmony);\n            } else if(platform == ProtoConstants.Platform.Platform_iPad || platform == ProtoConstants.Platform.Platform_APad || platform == ProtoConstants.Platform.Platform_HarmonyPad) {\n                statement.setInt(index++, ProtoConstants.Platform.Platform_iPad);\n                statement.setInt(index++, ProtoConstants.Platform.Platform_APad);\n                statement.setInt(index++, ProtoConstants.Platform.Platform_HarmonyPad);\n            } else if(platform == ProtoConstants.Platform.Platform_AndroidWearable || platform == ProtoConstants.Platform.Platform_HarmonyWearable) {\n                statement.setInt(index++, ProtoConstants.Platform.Platform_AndroidWearable);\n                statement.setInt(index++, ProtoConstants.Platform.Platform_HarmonyWearable);\n            } else if(platform == ProtoConstants.Platform.Platform_AndroidTV || platform == ProtoConstants.Platform.Platform_AppleTV || platform == ProtoConstants.Platform.Platform_HarmonyTV) {\n                statement.setInt(index++, ProtoConstants.Platform.Platform_AndroidTV);\n                statement.setInt(index++, ProtoConstants.Platform.Platform_AppleTV);\n                statement.setInt(index++, ProtoConstants.Platform.Platform_HarmonyTV);\n            } else {\n                statement.setInt(index++, platform);\n            }\n\n            statement.setString(index++, clientId);\n\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    void clearMultiUser(String uid, String clientId) {\n        long start = System.currentTimeMillis();\n        LOG.info(\"clearMultiUser {}, {}\", uid, clientId);\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"update t_user_session set _deleted = ?, _token = ?, _voip_token = ?, _dt = ?  where _cid = ? and _uid <> ? and _deleted = 0\";\n\n            statement = connection.prepareStatement(sql);\n            int index = 1;\n            statement.setInt(index++, 1);\n            statement.setString(index++, \"\");\n            statement.setString(index++, \"\");\n            statement.setLong(index++, System.currentTimeMillis());\n\n            statement.setString(index++, clientId);\n            statement.setString(index++, uid);\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    MemorySessionStore.Session createSession(String uid, String clientId, ClientSession clientSession, int platform) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        LOG.info(\"Database create session {},{}\", uid, clientId);\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"insert into t_user_session  (`_uid`,`_cid`,`_platform`,`_secret`,`_db_secret`, `_dt`) values (?,?,?,?,?,?)\";\n\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n\n            MemorySessionStore.Session session = new MemorySessionStore.Session(uid, clientId, clientSession);\n            session.setPlatform(platform);\n\n            statement.setString(index++, uid);\n            statement.setString(index++, clientId);\n            statement.setInt(index++, platform);\n\n\n            session.setSecret(UUID.randomUUID().toString());\n            statement.setString(index++, session.getSecret());\n\n            session.setDbSecret(UUID.randomUUID().toString());\n            statement.setString(index++, session.getDbSecret());\n\n            statement.setLong(index++, System.currentTimeMillis());\n\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n\n            return session;\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n        return null;\n    }\n\n    Set<String> getUserGroupIds(String userId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_gid` from t_group_member where `_mid` = ? and `_type` <> 4\";\n            statement = connection.prepareStatement(sql);\n\n            statement.setString(1, userId);\n\n            rs = statement.executeQuery();\n            Set<String> out = new HashSet<>();\n            while (rs.next()) {\n                String uid = rs.getString(1);\n                out.add(uid);\n            }\n            return out;\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n    Set<String> getUserGroupIds(String userId, List<Integer> memberTypes) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select _gid from t_group_member where _mid = ? \";\n            if(!memberTypes.isEmpty()) {\n                sql += \" and _type in (\";\n                for (int i = 0; i < memberTypes.size(); i++) {\n                    if(i > 0) {\n                        sql += \",\";\n                    }\n                    sql += memberTypes.get(i);\n                }\n                sql += \")\";\n            }\n            statement = connection.prepareStatement(sql);\n\n            statement.setString(1, userId);\n\n            rs = statement.executeQuery();\n            Set<String> out = new HashSet<>();\n            while (rs.next()) {\n                String uid = rs.getString(1);\n                out.add(uid);\n            }\n            return out;\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n\n    Set<String> getCommonGroupIds(String userId1, String userId2) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select t1._gid from t_group_member t1, t_group_member t2 where t1._mid = ? and t2._mid = ? and t1._type <> 4 and t2._type <> 4 and t1._gid = t2._gid\";\n            statement = connection.prepareStatement(sql);\n\n            statement.setString(1, userId1);\n            statement.setString(2, userId2);\n\n            rs = statement.executeQuery();\n            Set<String> out = new HashSet<>();\n            while (rs.next()) {\n                String uid = rs.getString(1);\n                out.add(uid);\n            }\n            return out;\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n    void updateGroupMemberDt(final String groupId, final long dt) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n\n            String sql = \"update t_group set `_member_dt` = ?, `_dt` = ? where `_gid` = ?\";\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setLong(index++, dt);\n            statement.setLong(index++, dt);\n            statement.setString(index++, groupId);\n\n            int c = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", c);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    void updateGroupMemberCountDt(final String groupId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n\n            String sql = \"update t_group set `_member_count` = (select count(*) from t_group_member where `_gid` = ? and `_type` <> 4 limit 1), `_dt` = ?, `_member_dt` = `_member_dt` + 1 where `_gid` = ?\";\n            statement = connection.prepareStatement(sql);\n            statement.setString(1, groupId);\n            statement.setLong(2, System.currentTimeMillis());\n            statement.setString(3, groupId);\n\n            int c = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", c);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    void persistGroupMember(final String groupId, final List<WFCMessage.GroupMember> memberList, boolean updateCreateTime) {\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                connection.setAutoCommit(false);\n\n                String sql = \"insert into t_group_member (`_gid`\" +\n                    \", `_mid`\" +\n                    \", `_alias`\" +\n                    \", `_type`\" +\n                    \", `_dt`, `_create_dt`, `_extra`) values(?, ?, ?, ?, ?, ?,?)\" +\n                    \" ON DUPLICATE KEY UPDATE \" +\n                    \"`_alias` = ?,\" +\n                    \"`_type` = ?,\" +\n                    \"`_dt` = ?,\" +\n                    \"`_extra` = ?\";\n                if(updateCreateTime) {\n                    sql += \", `_create_dt` = ?\";\n                }\n\n                statement = connection.prepareStatement(sql);\n\n                for (WFCMessage.GroupMember member : memberList\n                    ) {\n                    int index = 1;\n                    long dt = System.currentTimeMillis();\n                    if (member.getUpdateDt() > 0) {\n                        dt = member.getUpdateDt();\n                    }\n\n                    statement.setString(index++, groupId);\n                    statement.setString(index++, member.getMemberId());\n                    statement.setString(index++, member.getAlias());\n                    statement.setInt(index++, member.getType());\n                    statement.setLong(index++, dt);\n                    statement.setLong(index++, member.getCreateDt());\n                    statement.setString(index++, member.getExtra());\n                    statement.setString(index++, member.getAlias());\n                    statement.setInt(index++, member.getType());\n                    statement.setLong(index++, dt);\n                    statement.setString(index++, member.getExtra());\n                    if(updateCreateTime) {\n                        statement.setLong(index++, dt);\n                    }\n                    int count = statement.executeUpdate();\n                    LOG.info(\"Update rows {}\", count);\n                }\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                if (connection != null) {\n                    try {\n                        connection.commit();\n                        connection.setAutoCommit(true);\n                    } catch (SQLException e1) {\n                        e1.printStackTrace();\n                    }\n                }\n                DBUtil.closeDB(connection, statement);\n            }\n    }\n\n    int removeGroupMember(String groupId, List<String> groupMembers) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            StringBuilder sqlBuilder = new StringBuilder(\"update t_group_member set `_type` = ?, `_dt` = ? where `_mid` in (\");\n            for (int i = 0; i < groupMembers.size(); i++) {\n                sqlBuilder.append(\"?\");\n                if (i != groupMembers.size()-1) {\n                    sqlBuilder.append(\",\");\n                }\n            }\n            sqlBuilder.append(\")\");\n            sqlBuilder.append(\" and _gid = ?\");\n            statement = connection.prepareStatement(sqlBuilder.toString());\n\n            int index = 1;\n            long current = System.currentTimeMillis();\n            statement.setInt(index++, ProtoConstants.GroupMemberType.GroupMemberType_Removed);\n            statement.setLong(index++, current);\n\n            for (String memberId:groupMembers) {\n                statement.setString(index++, memberId);\n            }\n            statement.setString(index++, groupId);\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n        return 0;\n    }\n\n    WFCMessage.GroupInfo getPersistGroupInfo(String groupId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_name`\" +\n                \", `_portrait`\" +\n                \", `_owner`\" +\n                \", `_type`\" +\n                \", `_extra`\" +\n                \", `_dt`\" +\n                \", `_member_count`\" +\n                \", `_member_dt`\" +\n                \", `_mute`\" +\n                \", `_join_type`\" +\n                \", `_private_chat`\" +\n                \", `_searchable`\" +\n                \", _deleted\" +\n                \" from t_group  where `_gid` = ?\";\n\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setString(index++, groupId);\n\n            rs = statement.executeQuery();\n            if (rs.next()) {\n                String strValue;\n                int intValue;\n                WFCMessage.GroupInfo.Builder builder = WFCMessage.GroupInfo.newBuilder();\n                index = 1;\n\n                builder.setTargetId(groupId);\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setName(strValue);\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setPortrait(strValue);\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setOwner(strValue);\n\n                intValue = rs.getInt(index++);\n                builder.setType(intValue);\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setExtra(strValue);\n\n                long longValue = rs.getLong(index++);\n                builder.setUpdateDt(longValue);\n\n                intValue = rs.getInt(index++);\n                builder.setMemberCount(intValue);\n\n                longValue = rs.getLong(index++);\n                builder.setMemberUpdateDt(longValue);\n\n                intValue = rs.getInt(index++);\n                builder.setMute(intValue);\n\n                intValue = rs.getInt(index++);\n                builder.setJoinType(intValue);\n\n                intValue = rs.getInt(index++);\n                builder.setPrivateChat(intValue);\n\n                intValue = rs.getInt(index++);\n                builder.setSearchable(intValue);\n\n                intValue = rs.getInt(index++);\n                builder.setDeleted(intValue);\n\n                return builder.build();\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n    void updateChatroomInfo(String chatroomId, WFCMessage.ChatroomInfo chatroomInfo) {\n        LOG.info(\"Database update chatroom info {}\", chatroomId);\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"insert into t_chatroom (`_cid`\" +\n                    \", `_title`\" +\n                    \", `_portrait`\" +\n                    \", `_state`\" +\n                    \", `_desc`\" +\n                    \", `_extra`\" +\n                    \", `_dt`) values(?, ?, ?, ?, ?, ?, ?)\" +\n                    \" ON DUPLICATE KEY UPDATE `_title`=?\" +\n                    \", `_portrait`=?\" +\n                    \", `_state`=?\" +\n                    \", `_desc`=?\" +\n                    \", `_extra`=?\" +\n                    \", `_dt`=?\";\n\n                statement = connection.prepareStatement(sql);\n\n                int index = 1;\n\n                statement.setString(index++, chatroomId);\n                statement.setString(index++, chatroomInfo.getTitle());\n                statement.setString(index++, chatroomInfo.getPortrait());\n                statement.setInt(index++, chatroomInfo.getState());\n                statement.setString(index++, chatroomInfo.getDesc());\n                statement.setString(index++, chatroomInfo.getExtra());\n                statement.setLong(index++, chatroomInfo.getUpdateDt() == 0 ? System.currentTimeMillis() : chatroomInfo.getUpdateDt());\n\n                statement.setString(index++, chatroomInfo.getTitle());\n                statement.setString(index++, chatroomInfo.getPortrait());\n                statement.setInt(index++, chatroomInfo.getState());\n                statement.setString(index++, chatroomInfo.getDesc());\n                statement.setString(index++, chatroomInfo.getExtra());\n                statement.setLong(index++, chatroomInfo.getUpdateDt() == 0 ? System.currentTimeMillis() : chatroomInfo.getUpdateDt());\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    void removeChatroomInfo(String chatroomId) {\n        LOG.info(\"Database remove chatroom {}\", chatroomId);\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"delete from t_chatroom where `_cid`=?\";\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setString(index++, chatroomId);\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    WFCMessage.ChatroomInfo getPersistChatroomInfo(String chatroomId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_title`\" +\n                \", `_portrait`\" +\n                \", `_state`\" +\n                \", `_desc`\" +\n                \", `_extra`\" +\n                \", `_dt`\" +\n                \" from t_chatroom  where `_cid` = ?\";\n\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setString(index++, chatroomId);\n\n            rs = statement.executeQuery();\n            if (rs.next()) {\n                String strValue;\n                int intValue;\n                WFCMessage.ChatroomInfo.Builder builder = WFCMessage.ChatroomInfo.newBuilder();\n                index = 1;\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setTitle(strValue);\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setPortrait(strValue);\n\n                intValue = rs.getInt(index++);\n                builder.setState(intValue);\n\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setDesc(strValue);\n\n\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setExtra(strValue);\n\n\n\n                long longValue = rs.getLong(index++);\n                builder.setUpdateDt(longValue);\n                builder.setCreateDt(longValue);\n\n                return builder.build();\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n    void updateUserPassword(final String userId, final String password) {\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"update t_user set `_passwd_md5` = ? where `_uid` = ?\";\n\n                statement = connection.prepareStatement(sql);\n\n                int index = 1;\n\n                try {\n                    MessageDigest md5 = MessageDigest.getInstance(\"MD5\");\n                    String passwdMd5 = Base64.getEncoder().encodeToString(md5.digest(password.getBytes(\"utf-8\")));\n                    statement.setString(index, passwdMd5);\n                } catch (Exception e) {\n                    statement.setString(index, \"\");\n                }\n                index++;\n\n                statement.setString(index++, userId);\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    void deleteUser(final String userId) {\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"delete from t_user where `_uid`=?\";\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setString(index++, userId);\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    void deleteRobot(String robotId) {\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"delete from t_robot where `_uid`=?\";\n                statement = connection.prepareStatement(sql);\n                statement.setString(1, robotId);\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n    WFCMessage.Robot getRobot(String robotId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_owner`\" +\n                \", `_secret`\" +\n                \", `_callback`\" +\n                \", `_state`\" +\n                \", `_extra`\" +\n                \", `_dt` from t_robot where `_uid` = ?\";\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setString(1, robotId);\n\n\n            rs = statement.executeQuery();\n            if (rs.next()) {\n                WFCMessage.Robot.Builder builder = WFCMessage.Robot.newBuilder();\n                index = 1;\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setUid(robotId);\n                builder.setOwner(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setSecret(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setCallback(value);\n\n\n                int state = rs.getInt(index++);\n                builder.setState(state);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setExtra(value);\n\n                long longValue = rs.getLong(index++);\n\n                return builder.build();\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n    void updateRobot(final WFCMessage.Robot robot) {\n        LOG.info(\"Database update user info {}\", robot.getUid());\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"insert into t_robot (`_uid`\" +\n                    \", `_owner`\" +\n                    \", `_secret`\" +\n                    \", `_callback`\" +\n                    \", `_state`\" +\n                    \", `_extra`\" +\n                    \", `_dt`) values(?, ?, ?, ?, ?, ?, ?)\" +\n                    \" ON DUPLICATE KEY UPDATE `_owner`=?\" +\n                    \", `_secret`=?\" +\n                    \", `_callback`=?\" +\n                    \", `_state`=?\" +\n                    \", `_extra`=?\" +\n                    \", `_dt`=?\";\n\n                statement = connection.prepareStatement(sql);\n\n                int index = 1;\n\n                statement.setString(index++, robot.getUid());\n                statement.setString(index++, robot.getOwner());\n                statement.setString(index++, robot.getSecret());\n                statement.setString(index++, robot.getCallback());\n                statement.setInt(index++, robot.getState());\n                statement.setString(index++, robot.getExtra());\n                statement.setLong(index++, System.currentTimeMillis());\n\n                statement.setString(index++, robot.getOwner());\n                statement.setString(index++, robot.getSecret());\n                statement.setString(index++, robot.getCallback());\n                statement.setInt(index++, robot.getState());\n                statement.setString(index++, robot.getExtra());\n                statement.setLong(index++, System.currentTimeMillis());\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n    \n    boolean isUidAndNameConflict(String uid, String name) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        long start = System.currentTimeMillis();\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select _uid from t_user where _name = ? and _uid <> ? limit 1\";\n            statement = connection.prepareStatement(sql);\n            statement.setString(1, name);\n            statement.setString(2, uid);\n            rs = statement.executeQuery();\n            if (rs.next()) {\n                String conflictId = rs.getString(1);\n                LOG.error(\"user {} already have name {} !!!\", conflictId, name);\n                return true;\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return false;\n    }\n\n    void updateUser(final WFCMessage.User user) throws Exception {\n        LOG.info(\"Database update user info {} {}\", user.getUid(), user.getUpdateDt());\n            Connection connection = null;\n            PreparedStatement statement = null;\n            LOG.info(\"Database update user info {}\", user.getDisplayName());\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"insert into t_user (`_uid`\" +\n                    \", `_name`\" +\n                    \", `_display_name`\" +\n                    \", `_portrait`\" +\n                    \", `_mobile`\" +\n                    \", `_gender`\" +\n                    \", `_email`\" +\n                    \", `_address`\" +\n                    \", `_company`\" +\n                    \", `_social`\" +\n                    \", `_extra`\" +\n                    \", `_type`\" +\n                    \", `_dt`) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\" +\n                \" ON DUPLICATE KEY UPDATE `_name`=?\" +\n                    \", `_display_name`=?\" +\n                    \", `_portrait`=?\" +\n                    \", `_mobile`=?\" +\n                    \", `_gender`=?\" +\n                    \", `_email`=?\" +\n                    \", `_address`=?\" +\n                    \", `_company`=?\" +\n                    \", `_social`=?\" +\n                    \", `_extra`=?\" +\n                    \", `_type`=?\" +\n                    \", `_deleted`=?\" +\n                    \", `_dt`=?\";\n\n                statement = connection.prepareStatement(sql);\n\n                int index = 1;\n\n                statement.setString(index++, user.getUid());\n                statement.setString(index++, user.getName());\n                statement.setString(index++, user.getDisplayName());\n                statement.setString(index++, user.getPortrait());\n                statement.setString(index++, user.getMobile());\n                statement.setInt(index++, user.getGender());\n                statement.setString(index++, user.getEmail());\n                statement.setString(index++, user.getAddress());\n                statement.setString(index++, user.getCompany());\n                statement.setString(index++, user.getSocial());\n\n                statement.setString(index++, user.getExtra());\n                statement.setInt(index++, user.getType());\n                statement.setLong(index++, user.getUpdateDt() == 0 ? System.currentTimeMillis() : user.getUpdateDt());\n\n                statement.setString(index++, user.getName());\n                statement.setString(index++, user.getDisplayName());\n                statement.setString(index++, user.getPortrait());\n                statement.setString(index++, user.getMobile());\n                statement.setInt(index++, user.getGender());\n                statement.setString(index++, user.getEmail());\n                statement.setString(index++, user.getAddress());\n                statement.setString(index++, user.getCompany());\n                statement.setString(index++, user.getSocial());\n\n                statement.setString(index++, user.getExtra());\n                statement.setInt(index++, user.getType());\n                statement.setInt(index++, user.getDeleted());\n                statement.setLong(index++, user.getUpdateDt() == 0 ? System.currentTimeMillis() : user.getUpdateDt());\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n                throw new Exception(e.getMessage());\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n    }\n\n    void deleteUserStatus(String userId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"delete from t_user_status where _uid = ?\";\n            statement = connection.prepareStatement(sql);\n            statement.setString(1, userId);\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    void updateUserStatus(String userId, int status) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            if (status == 0) {\n                String sql = \"delete from t_user_status where _uid = ?\";\n                statement = connection.prepareStatement(sql);\n                statement.setString(1, userId);\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } else {\n                String sql = \"insert into t_user_status (`_uid`, `_status`, `_dt`) values(?,?,?) ON DUPLICATE KEY UPDATE `_status` = ?\";\n\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setString(index++, userId);\n                statement.setInt(index++, status);\n                statement.setLong(index++,  System.currentTimeMillis());\n                statement.setInt(index++, status);\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    int getGeneratedId() {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"INSERT INTO `t_id_generator` (`id`) VALUES (NULL);\";\n\n            statement = connection.prepareStatement(sql);\n            if(statement.executeUpdate()> 0) {\n                sql = \"SELECT LAST_INSERT_ID()\";\n\n                try {\n                    if (statement!=null) {\n                        statement.close();\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, RDBS_Exception);\n                }\n\n                statement = connection.prepareStatement(sql);\n\n                rs = statement.executeQuery();\n                if (rs.next()) {\n                    return rs.getInt(1);\n                }\n            }\n\n            return -1;\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n            return -1;\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n    }\n\n    WFCMessage.User getPersistUser(String userId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_name`\" +\n                \", `_display_name`\" +\n                \", `_portrait`\" +\n                \", `_mobile`\" +\n                \", `_gender`\" +\n                \", `_email`\" +\n                \", `_address`\" +\n                \", `_company`\" +\n                \", `_social`\" +\n                \", `_extra`\" +\n                \", `_type`\" +\n                \", `_deleted`\" +\n                \", `_dt` from t_user where `_uid` = ?\";\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setString(1, userId);\n\n\n            rs = statement.executeQuery();\n            if (rs.next()) {\n                WFCMessage.User.Builder builder = WFCMessage.User.newBuilder();\n                index = 1;\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setUid(userId);\n                builder.setName(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setDisplayName(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setPortrait(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setMobile(value);\n\n                int gender = rs.getInt(index++);\n                builder.setGender(gender);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setEmail(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setAddress(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setCompany(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setSocial(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setExtra(value);\n\n                int type = rs.getInt(index++);\n                builder.setType(type);\n\n                int deleted = rs.getInt(index++);\n                builder.setDeleted(deleted);\n\n                long longValue = rs.getLong(index++);\n                if(longValue <= 0)\n                    longValue = 1;\n                builder.setUpdateDt(longValue);\n\n                return builder.build();\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n    String getUserIdByName(String name) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_uid` from t_user where `_name` = ? limit 1\";\n            statement = connection.prepareStatement(sql);\n            statement.setString(1, name);\n            rs = statement.executeQuery();\n            if (rs.next()) {\n                return rs.getString(1);\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n    String getUserIdByMobile(String mobile) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_uid` from t_user where `_mobile` = ? limit 1\";\n            statement = connection.prepareStatement(sql);\n            statement.setString(1, mobile);\n            rs = statement.executeQuery();\n            if (rs.next()) {\n                return rs.getString(1);\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n    List<WFCMessage.User> getUserInfosByEmail(String email) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        List<WFCMessage.User> outList = new ArrayList<>();\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_uid`, `_name`\" +\n                \", `_display_name`\" +\n                \", `_portrait`\" +\n                \", `_mobile`\" +\n                \", `_gender`\" +\n                \", `_email`\" +\n                \", `_address`\" +\n                \", `_company`\" +\n                \", `_social`\" +\n                \", `_extra`\" +\n                \", `_type`\" +\n                \", `_deleted`\" +\n                \", `_dt` from t_user where `_deleted` = 0 and `_email` = ?\";\n            statement = connection.prepareStatement(sql);\n            statement.setString(1, email);\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                WFCMessage.User.Builder builder = WFCMessage.User.newBuilder();\n                int index = 1;\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setUid(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setName(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setDisplayName(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setPortrait(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setMobile(value);\n\n                int gender = rs.getInt(index++);\n                builder.setGender(gender);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setEmail(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setAddress(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setCompany(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setSocial(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setExtra(value);\n\n                int type = rs.getInt(index++);\n                builder.setType(type);\n\n                int deleted = rs.getInt(index++);\n                builder.setDeleted(deleted);\n\n                long longValue = rs.getLong(index++);\n                if(longValue <= 0)\n                    longValue = 1;\n                builder.setUpdateDt(longValue);\n\n                outList.add(builder.build());\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return outList;\n    }\n\n    List<WFCMessage.User> getAllUsers(int count, int offset) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        List<WFCMessage.User> outList = new ArrayList<>();\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_uid`, `_name`\" +\n                \", `_display_name`\" +\n                \", `_portrait`\" +\n                \", `_mobile`\" +\n                \", `_gender`\" +\n                \", `_email`\" +\n                \", `_address`\" +\n                \", `_company`\" +\n                \", `_social`\" +\n                \", `_extra`\" +\n                \", `_type`\" +\n                \", `_deleted`\" +\n                \", `_dt` from t_user where `_deleted` = 0 order by _createTime limit ? offset ?\";\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setInt(1, count);\n            statement.setInt(2, offset);\n\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                WFCMessage.User.Builder builder = WFCMessage.User.newBuilder();\n                index = 1;\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setUid(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setName(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setDisplayName(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setPortrait(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setMobile(value);\n\n                int gender = rs.getInt(index++);\n                builder.setGender(gender);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setEmail(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setAddress(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setCompany(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setSocial(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setExtra(value);\n\n                int type = rs.getInt(index++);\n                builder.setType(type);\n\n                int deleted = rs.getInt(index++);\n                builder.setDeleted(deleted);\n\n                long longValue = rs.getLong(index++);\n                if(longValue <= 0)\n                    longValue = 1;\n                builder.setUpdateDt(longValue);\n\n                outList.add(builder.build());\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return outList;\n    }\n\n    List<String> getUserRobotIds(String userId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        List<String> outList = new ArrayList<>();\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select _uid from t_robot where _owner = ? and _state = 0\";\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setString(1, userId);\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                outList.add(rs.getString(1));\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return outList;\n    }\n\n\n    Set<String> getAllEnds(boolean fromUserTable) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql;\n            if(fromUserTable) {\n                sql = \"select distinct(`_uid`) from t_user_session\";\n            } else {\n                sql = \"select distinct(`_uid`) from t_user where `_deleted` = 0 and `_type` <> 1 and `_type` <> 2\";\n            }\n            statement = connection.prepareStatement(sql);\n\n            rs = statement.executeQuery();\n            Set<String> out = new HashSet<>();\n            while (rs.next()) {\n                String uid = rs.getString(1);\n                out.add(uid);\n            }\n            return out;\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n    List<FriendData> getPersistFriends(String userId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_friend_uid`, `_alias`, `_state`, `_blacked`, `_dt`, `_extra` from t_friend where `_uid` = ?\";\n            statement = connection.prepareStatement(sql);\n\n\n            int index = 1;\n            statement.setString(index++, userId);\n\n\n            rs = statement.executeQuery();\n            List<FriendData> out = new ArrayList<>();\n            while (rs.next()) {\n                String uid = rs.getString(1);\n                String alias = rs.getString(2);\n                int state = rs.getInt(3);\n                int blacked = rs.getInt(4);\n                long timestamp = rs.getLong(5);\n                String extra = rs.getString(6);\n\n                FriendData data = new FriendData(userId, uid, alias, extra, state, blacked, timestamp);\n                out.add(data);\n            }\n            return out;\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n\n    void removeUserFriend(String userId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"update t_friend  set `_alias` = '', `_state` = 1, `_blacked` = 0, `_dt` = ?, `_extra` = 0 where `_uid` = ? or `_friend_uid` = ?\";\n\n            statement = connection.prepareStatement(sql);\n            int index = 1;\n            statement.setLong(index++, System.currentTimeMillis());\n            statement.setString(index++, userId);\n            statement.setString(index++, userId);\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    void removeUserFriendRequest(String userId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"delete from t_friend_request  where _uid = ? or _friend_uid = ?\";\n\n            statement = connection.prepareStatement(sql);\n            int index = 1;\n            statement.setString(index++, userId);\n            statement.setString(index++, userId);\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    List<WFCMessage.FriendRequest> getPersistFriendRequests(String userId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select  `_uid`\" +\n                \", `_friend_uid`\" +\n                \", `_reason`\" +\n                \", `_status`\" +\n                \", `_dt`\" +\n                \", `_from_read_status`\" +\n                \", `_to_read_status`, `_extra` from t_friend_request where `_uid` = ? UNION ALL \" +\n                \"select   `_uid`\" +\n                \", `_friend_uid`\" +\n                \", `_reason`\" +\n                \", `_status`\" +\n                \", `_dt`\" +\n                \", `_from_read_status`\" +\n                \", `_to_read_status`, `_extra` from t_friend_request where `_friend_uid` = ?\";\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setString(index++, userId);\n            statement.setString(index++, userId);\n\n\n            rs = statement.executeQuery();\n            List<WFCMessage.FriendRequest> out = new ArrayList<>();\n            while (rs.next()) {\n                WFCMessage.FriendRequest.Builder builder = WFCMessage.FriendRequest.newBuilder();\n                index = 1;\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setFromUid(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setToUid(value);\n\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setReason(value);\n\n                int intValue = rs.getInt(index++);\n                builder.setStatus(intValue);\n\n                long longValue = rs.getLong(index++);\n                builder.setUpdateDt(longValue);\n\n                boolean b = rs.getBoolean(index++);\n                builder.setFromReadStatus(b);\n\n                b = rs.getBoolean(index++);\n                builder.setToReadStatus(b);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setExtra(value);\n\n                out.add(builder.build());\n            }\n            return out;\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n    void persistFriendRequestUnreadStatus(String userId, long readDt, long updateDt) {\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"update t_friend_request set `_dt`=? , `_to_read_status`=?\" +\n                    \" where \" +\n                    \"`_friend_uid` = ? and\" +\n                    \"`_dt` <= ? and\" +\n                    \"`_to_read_status` = ?\";\n\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setLong(index++, updateDt);\n                statement.setBoolean(index++, true);\n                statement.setString(index++, userId);\n                statement.setLong(index++, readDt);\n                statement.setBoolean(index++, false);\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n    }\n    //\n    void persistOrUpdateFriendRequest(final WFCMessage.FriendRequest request) {\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"insert into t_friend_request (`_uid`, `_friend_uid`, `_reason`, `_status`, `_dt`, `_from_read_status`, `_to_read_status`, `_extra`) values(?, ?, ?, ?, ?, ?, ?, ?)\" +\n                    \" ON DUPLICATE KEY UPDATE \" +\n                    \"`_reason` = ?,\" +\n                    \"`_status` = ?,\" +\n                    \"`_dt` = ?,\" +\n                    \"`_from_read_status` = ?,\" +\n                    \"`_to_read_status` = ?,\" +\n                    \"`_extra` = ?\";\n\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setString(index++, request.getFromUid());\n                statement.setString(index++, request.getToUid());\n                statement.setString(index++, request.getReason());\n                statement.setInt(index++, request.getStatus());\n                statement.setLong(index++, request.getUpdateDt());\n                statement.setInt(index++, request.getFromReadStatus() ? 1 : 0);\n                statement.setInt(index++, request.getToReadStatus() ? 1 : 0);\n                statement.setString(index++, request.getExtra());\n\n                statement.setString(index++, request.getReason());\n                statement.setInt(index++, request.getStatus());\n                statement.setLong(index++, request.getUpdateDt());\n                statement.setInt(index++, request.getFromReadStatus() ? 1 : 0);\n                statement.setInt(index++, request.getToReadStatus() ? 1 : 0);\n                statement.setString(index++, request.getExtra());\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n    }\n\n    void persistOrUpdateFriendData(final FriendData request) {\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"insert into t_friend (`_uid`, `_friend_uid`, `_alias`, `_state`, `_blacked`, `_dt`, `_extra`) values(?, ?, ?, ?, ?, ?, ?)\" +\n                    \" ON DUPLICATE KEY UPDATE \" +\n                    \"`_alias` = ?,\" +\n                    \"`_state` = ?,\" +\n                    \"`_blacked` = ?,\" +\n                    \"`_dt` = ?,\" +\n                    \"`_extra` = ?\";\n\n\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setString(index++, request.getUserId());\n                statement.setString(index++, request.getFriendUid());\n                statement.setString(index++, request.getAlias());\n                statement.setInt(index++, request.getState());\n                statement.setInt(index++, request.getBlacked());\n                statement.setLong(index++, request.getTimestamp());\n                statement.setString(index++, request.getExtra());\n                statement.setString(index++, request.getAlias());\n                statement.setInt(index++, request.getState());\n                statement.setInt(index++, request.getBlacked());\n                statement.setLong(index++, request.getTimestamp());\n                statement.setString(index++, request.getExtra());\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n    }\n\n    boolean removeGroupInfoFromDB(String groupId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql;\n            if(keepGroupInfo) {\n                sql = \"update t_group set _deleted = 1, _dt = _dt+1, _member_count = 0, _member_dt = _member_dt+1 where _gid = ?\";\n            } else {\n                sql = \"delete from t_group where _gid = ?\";\n            }\n\n            statement = connection.prepareStatement(sql);\n            int index = 1;\n            statement.setString(index++, groupId);\n            return statement.executeUpdate() > 0;\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n        return false;\n    }\n\n    boolean removeGroupMemberFromDB(String groupId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"delete from t_group_member where _gid = ?\";\n\n            statement = connection.prepareStatement(sql);\n            int index = 1;\n            statement.setString(index++, groupId);\n            return statement.executeUpdate() > 0;\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n        return false;\n    }\n\n    void updateChannelInfo(final WFCMessage.ChannelInfo channelInfo) {\n        LOG.info(\"Database update channel info {} {}\", channelInfo.getTargetId(), channelInfo.getUpdateDt());\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"insert into t_channel (`_cid`\" +\n                    \", `_name`\" +\n                    \", `_portrait`\" +\n                    \", `_owner`\" +\n                    \", `_status`\" +\n                    \", `_desc`\" +\n                    \", `_extra`\" +\n                    \", `_secret`\" +\n                    \", `_callback`\" +\n                    \", `_automatic`\" +\n                    \", `_menu`\" +\n                    \", `_dt`) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\" +\n                    \" ON DUPLICATE KEY UPDATE `_name`=?\" +\n                    \", `_portrait`=?\" +\n                    \", `_owner`=?\" +\n                    \", `_status`=?\" +\n                    \", `_desc`=?\" +\n                    \", `_extra`=?\" +\n                    \", `_secret`=?\" +\n                    \", `_callback`=?\" +\n                    \", `_automatic`=?\" +\n                    \", `_menu`=?\" +\n                    \", `_dt`=?\";\n\n                statement = connection.prepareStatement(sql);\n\n                WFCMessage.ChannelMenuList.Builder builder = WFCMessage.ChannelMenuList.newBuilder();\n                if (!channelInfo.getMenuList().isEmpty()) {\n                    for (WFCMessage.ChannelMenu menuBtn:channelInfo.getMenuList()) {\n                        builder.addMenu(menuBtn);\n                    }\n                }\n                byte[] menuBytes = builder.build().toByteArray();\n\n                int index = 1;\n                statement.setString(index++, channelInfo.getTargetId());\n                statement.setString(index++, channelInfo.getName());\n                statement.setString(index++, channelInfo.getPortrait());\n                statement.setString(index++, channelInfo.getOwner());\n                statement.setInt(index++, channelInfo.getStatus());\n                statement.setString(index++, channelInfo.getDesc());\n                statement.setString(index++, channelInfo.getExtra());\n                statement.setString(index++, channelInfo.getSecret());\n                statement.setString(index++, channelInfo.getCallback());\n                statement.setInt(index++, channelInfo.getAutomatic());\n                statement.setBytes(index++, menuBytes);\n                statement.setLong(index++, channelInfo.getUpdateDt() == 0 ? System.currentTimeMillis() : channelInfo.getUpdateDt());\n\n                statement.setString(index++, channelInfo.getName());\n                statement.setString(index++, channelInfo.getPortrait());\n                statement.setString(index++, channelInfo.getOwner());\n                statement.setInt(index++, channelInfo.getStatus());\n                statement.setString(index++, channelInfo.getDesc());\n                statement.setString(index++, channelInfo.getExtra());\n                statement.setString(index++, channelInfo.getSecret());\n                statement.setString(index++, channelInfo.getCallback());\n                statement.setInt(index++, channelInfo.getAutomatic());\n                statement.setBytes(index++, menuBytes);\n                statement.setLong(index++, channelInfo.getUpdateDt() == 0 ? System.currentTimeMillis() : channelInfo.getUpdateDt());\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n    }\n\n    void removeChannelInfo(final String channelId) {\n        LOG.info(\"Database remove channel {}\", channelId);\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                String sql = \"delete from t_channel where `_cid`=?\";\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setString(index++, channelId);\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    WFCMessage.ChannelInfo getPersistChannelInfo(String channelId) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_name`\" +\n                \", `_portrait`\" +\n                \", `_owner`\" +\n                \", `_status`\" +\n                \", `_desc`\" +\n                \", `_extra`\" +\n                \", `_secret`\" +\n                \", `_callback`\" +\n                \", `_automatic`\" +\n                \", `_menu`\" +\n                \", `_dt` from t_channel  where `_cid` = ?\";\n\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setString(index++, channelId);\n\n            rs = statement.executeQuery();\n            if (rs.next()) {\n                String strValue;\n                int intValue;\n                WFCMessage.ChannelInfo.Builder builder = WFCMessage.ChannelInfo.newBuilder();\n                index = 1;\n\n                builder.setTargetId(channelId);\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setName(strValue);\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setPortrait(strValue);\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setOwner(strValue);\n\n                intValue = rs.getInt(index++);\n                builder.setStatus(intValue);\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setDesc(strValue);\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setExtra(strValue);\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setSecret(strValue);\n\n                strValue = rs.getString(index++);\n                strValue = (strValue == null ? \"\" : strValue);\n                builder.setCallback(strValue);\n\n                intValue = rs.getInt(index++);\n                builder.setAutomatic(intValue);\n\n                try {\n                    byte[] bytes = null;\n                    Blob blob = rs.getBlob(index++);\n                    if (blob != null) {\n                        bytes = toByteArray(blob.getBinaryStream());\n                    }\n\n                    WFCMessage.ChannelMenuList menuButtonList = WFCMessage.ChannelMenuList.parseFrom(bytes);\n                    if (menuButtonList.getMenuCount() > 0) {\n                        builder.addAllMenu(menuButtonList.getMenuList());\n                    }\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n\n                long longValue = rs.getLong(index++);\n                builder.setUpdateDt(longValue);\n\n                return builder.build();\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return null;\n    }\n\n\n    void persistChannelListener(final String groupId, final List<String> memberList) {\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n                connection.setAutoCommit(false);\n\n                String sql = \"insert into t_channel_listener (`_cid`\" +\n                    \", `_mid`\" +\n                    \", `_dt`) values(?, ?, ?)\" +\n                    \" ON DUPLICATE KEY UPDATE \" +\n                    \"`_dt` = ?\";\n\n                statement = connection.prepareStatement(sql);\n\n                long dt = System.currentTimeMillis();\n                for (String member : memberList) {\n                    int index = 1;\n                    statement.setString(index++, groupId);\n                    statement.setString(index++, member);\n                    statement.setLong(index++, dt);\n                    statement.setLong(index++, dt);\n                    int count = statement.executeUpdate();\n                    LOG.info(\"Update rows {}\", count);\n                }\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                if (connection != null) {\n                    try {\n                        connection.commit();\n                        connection.setAutoCommit(true);\n                    } catch (SQLException e1) {\n                        e1.printStackTrace();\n                    }\n                }\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    List<String> getChannelListener(String channelId) {\n        List<String> out = new ArrayList<>();\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_mid` from t_channel_listener where _cid = ?\";\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setString(index++, channelId);\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n\n                String value = rs.getString(1);\n                if (!StringUtil.isNullOrEmpty(value)) {\n                    out.add(value);\n                }\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return out;\n    }\n\n    List<WFCMessage.ChannelInfo> searchChannelFromDB(String keyword, boolean buzzy, int page) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n\n        ArrayList<WFCMessage.ChannelInfo> out = new ArrayList<>();\n\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_cid`, `_name`\" +\n                \", `_portrait`\" +\n                \", `_owner`\" +\n                \", `_status`\" +\n                \", `_desc`\" +\n                \", `_extra`\" +\n                \", `_dt` from t_channel\";\n            if (buzzy) {\n                sql += \" where `_name` like ? ESCAPE '!' \";\n            } else {\n                sql += \" where `_name` = ?\";\n            }\n\n            sql += \" and _status <> 64\";\n            sql += \" and _status <> 16\";\n            sql += \" and _status <> 17\";\n            sql += \" and _status <> 24\";\n            sql += \" and _status <> 25\";\n\n            sql += \" limit 20\";\n\n\n            if (page > 0) {\n                sql += \" offset \" + page * 20;\n            }\n\n            keyword = keyword\n                .replace(\"!\", \"!!\")\n                .replace(\"%\", \"!%\")\n                .replace(\"_\", \"!_\")\n                .replace(\"[\", \"![\");\n\n            statement = connection.prepareStatement(sql);\n            int index = 1;\n            if (buzzy) {\n                statement.setString(index++, \"%\" + keyword + \"%\");\n            } else {\n                statement.setString(index++, keyword);\n            }\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                WFCMessage.ChannelInfo.Builder builder = WFCMessage.ChannelInfo.newBuilder();\n                index = 1;\n\n                String value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setTargetId(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setName(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setPortrait(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setOwner(value);\n\n                int status = rs.getInt(index++);\n                builder.setStatus(status);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setDesc(value);\n\n                value = rs.getString(index++);\n                value = (value == null ? \"\" : value);\n                builder.setExtra(value);\n\n                long longValue = rs.getLong(index++);\n                builder.setUpdateDt(longValue);\n\n                out.add(builder.build());\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return out;\n    }\n\n    void updateChannelListener(final String channelId, final String listener, final boolean listen) {\n        LOG.info(\"updateChannelListener channel {}, listener {}, listen {}\", channelId, listener, listen);\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql;\n            if (listen) {\n                sql = \"insert into t_channel_listener (`_cid`\" +\n                    \", `_mid`\" +\n                    \", `_dt`) values(?, ?, ?)\" +\n                    \" ON DUPLICATE KEY UPDATE \" +\n                    \"`_dt` = ?\";\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setString(index++, channelId);\n                statement.setString(index++, listener);\n                statement.setLong(index++, System.currentTimeMillis());\n                statement.setLong(index++, System.currentTimeMillis());\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } else {\n                sql = \"delete from t_channel_listener where `_cid`=? and `_mid`=?\";\n\n                statement = connection.prepareStatement(sql);\n                int index = 1;\n                statement.setString(index++, channelId);\n                statement.setString(index++, listener);\n\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    List<String> getUserChannels(String userId) {\n        List<String> out = new ArrayList<>();\n\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select _cid from t_channel_listener where _mid = ?\";\n            statement = connection.prepareStatement(sql);\n\n            int index = 1;\n            statement.setString(index++, userId);\n\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                String value = rs.getString(1);\n                if (!StringUtil.isNullOrEmpty(value)) {\n                    out.add(value);\n                }\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return out;\n    }\n\n    void clearChannelListener(final String channelId) {\n        LOG.info(\"Database remove channel {}\", channelId);\n        Connection connection = null;\n        PreparedStatement statement = null;\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"delete from t_channel_listener where _cid=?\";\n            statement = connection.prepareStatement(sql);\n            statement.setString(1, channelId);\n            int count = statement.executeUpdate();\n            LOG.info(\"Update rows {}\", count);\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement);\n        }\n    }\n\n    public Set<String> getSensitiveWord() {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n\n        Set<String> out = new HashSet<>();\n\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"select `_word` from t_sensitiveword order by `id` desc\";\n\n            statement = connection.prepareStatement(sql);\n            rs = statement.executeQuery();\n            while (rs.next()) {\n                String value = rs.getString(1);\n                out.add(value);\n            }\n        } catch (SQLException e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n        return out;\n    }\n\n    void deleteSensitiveWord(final String word) {\n        LOG.info(\"delete sensitive word {}\", word);\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n\n                String sql = \"delete from t_sensitiveword where `_word` = ?\";\n                statement = connection.prepareStatement(sql);\n\n                statement.setString(1, word);\n                int c = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", c);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    void persistSensitiveWord(final String word) {\n        mScheduler.execute(()->{\n            Connection connection = null;\n            PreparedStatement statement = null;\n            try {\n                connection = DBUtil.getConnection();\n\n                String sql = \"insert into t_sensitiveword (`_word`) values(?)\";\n\n                statement = connection.prepareStatement(sql);\n                statement.setString(1, word);\n                int count = statement.executeUpdate();\n                LOG.info(\"Update rows {}\", count);\n            } catch (SQLException e) {\n                // TODO Auto-generated catch block\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, RDBS_Exception);\n            } finally {\n                DBUtil.closeDB(connection, statement);\n            }\n        });\n    }\n\n    private String getUserMessageTable(String uid) {\n        if (DBUtil.IsEmbedDB) {\n            return \"t_user_messages\";\n        }\n        int hashId = Math.abs(uid.hashCode())%128;\n        return \"t_user_messages_\" + hashId;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/GroupLoader.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.persistence;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.core.MapLoader;\nimport com.hazelcast.core.MapStore;\nimport io.moquette.server.Server;\n\nimport java.util.Collection;\nimport java.util.Map;\n\npublic class GroupLoader implements MapStore<String, WFCMessage.GroupInfo> {\n    private DatabaseStore getDatabaseStore() {\n        return Server.getServer().getStore().messagesStore().getDatabaseStore();\n    }\n\n    /**\n     * Loads the value of a given key. If distributed map doesn't contain the value\n     * for the given key then Hazelcast will call implementation's load (key) method\n     * to obtain the value. Implementation can use any means of loading the given key;\n     * such as an O/R mapping tool, simple SQL or reading a file etc.\n     *\n     * @param key@return value of the key, value cannot be null\n     */\n    @Override\n    public WFCMessage.GroupInfo load(String key) {\n        return getDatabaseStore().getPersistGroupInfo(key);\n    }\n\n    /**\n     * Loads given keys. This is batch load operation so that implementation can\n     * optimize the multiple loads.\n     * <p>\n     * For any key in the input keys, there should be a single mapping in the resulting map. Also the resulting\n     * map should not have any keys that are not part of the input keys.\n     * <p>\n     * The given collection should not contain any <code>null</code> keys.\n     * The returned Map should not contain any <code>null</code> keys or values.\n     *\n     * @param keys keys of the values entries to load\n     * @return map of loaded key-value pairs.\n     */\n    @Override\n    public Map<String, WFCMessage.GroupInfo> loadAll(Collection<String> keys) {\n        return null;\n    }\n\n\n    @Override\n    public Iterable<String> loadAllKeys() {\n        return null;\n    }\n\n    @Override\n    public void store(String key, WFCMessage.GroupInfo value) {\n        getDatabaseStore().persistGroupInfo(value);\n    }\n\n    @Override\n    public void storeAll(Map<String, WFCMessage.GroupInfo> map) {\n        for (WFCMessage.GroupInfo value : map.values()) {\n            getDatabaseStore().persistGroupInfo(value);\n        }\n    }\n\n    @Override\n    public void delete(String key) {\n        getDatabaseStore().removeGroupInfoFromDB(key);\n    }\n\n    @Override\n    public void deleteAll(Collection<String> keys) {\n\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/MemoryMessagesStore.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.persistence;\n\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.google.protobuf.ByteString;\nimport com.hazelcast.core.*;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.RestResult;\nimport com.xiaoleilu.loServer.action.Action;\nimport com.xiaoleilu.loServer.action.admin.AdminAction;\nimport com.xiaoleilu.loServer.model.FriendData;\nimport cn.wildfirechat.common.ErrorCode;\nimport io.moquette.BrokerConstants;\nimport io.moquette.imhandler.IMHandler;\nimport io.moquette.server.Constants;\nimport io.moquette.server.Server;\nimport io.moquette.spi.IMatchingCondition;\nimport io.moquette.spi.IMessagesStore;\nimport io.moquette.spi.impl.security.AES;\nimport io.moquette.spi.security.Tokenor;\nimport io.moquette.spi.impl.subscriptions.Topic;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.handler.codec.mqtt.MqttVersion;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.json.simple.JSONObject;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.*;\n\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReadWriteLock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\nimport java.util.function.BiFunction;\nimport java.util.function.Consumer;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport static cn.wildfirechat.common.IMExceptionEvent.EventType.EVENT_CALLBACK_Exception;\nimport static cn.wildfirechat.proto.ProtoConstants.ChannelState.*;\nimport static cn.wildfirechat.proto.ProtoConstants.ChannelUpdateEventType.*;\nimport static cn.wildfirechat.proto.ProtoConstants.ChatroomMemberUpdateEventType.Chatroom_Member_Event_Join;\nimport static cn.wildfirechat.proto.ProtoConstants.ChatroomMemberUpdateEventType.Chatroom_Member_Event_Leave;\nimport static cn.wildfirechat.proto.ProtoConstants.ChatroomUpdateEventType.Chatroom_Event_Create;\nimport static cn.wildfirechat.proto.ProtoConstants.ChatroomUpdateEventType.Chatroom_Event_Destroy;\nimport static cn.wildfirechat.proto.ProtoConstants.GroupMemberType.*;\nimport static cn.wildfirechat.proto.ProtoConstants.ModifyChannelInfoType.*;\nimport static cn.wildfirechat.proto.ProtoConstants.ModifyGroupInfoType.*;\nimport static cn.wildfirechat.proto.ProtoConstants.PersistFlag.Transparent;\nimport static cn.wildfirechat.proto.ProtoConstants.Platform.*;\nimport static cn.wildfirechat.proto.ProtoConstants.UpdateUserInfoMask.*;\nimport static io.moquette.BrokerConstants.*;\nimport static io.moquette.server.Constants.MAX_CHATROOM_MESSAGE_QUEUE;\nimport static io.moquette.server.Constants.MAX_MESSAGE_QUEUE;\nimport static cn.wildfirechat.pojos.MyInfoType.*;\nimport static win.liyufan.im.UserSettingScope.*;\n\npublic class MemoryMessagesStore implements IMessagesStore {\n    private static final String MESSAGES_MAP = \"messages_map\";\n    private static final String GROUPS_MAP = \"groups_map\";\n    static int dumy = 0;\n    static final String GROUP_MEMBERS = \"group_members\";\n\n    private static final String CHATROOM_MEMBER_IDS = \"chatroom_members\";\n    private static final String USER_CHATROOM = \"user_chatroom\";\n\n    static final String USER_FRIENDS = \"user_friends\";\n    static final String USER_FRIENDS_REQUEST = \"user_friends_request\";\n\n    static final String USERS = \"users\";\n\n    static final String USER_STATUS = \"user_status\";\n\n    private static final String CHATROOMS = \"chatrooms\";\n\n    private static final String USER_SETTING = \"user_setting\";\n\n    private static final String CHANNELS = \"channels_map\";\n\n    private static final String CHANNEL_LISTENERS = \"channel_listeners\";\n\n    private static boolean IS_MESSAGE_ROAMING = true;\n    private static long msgCompensateTimeLimit = 300000;\n\n    private static boolean IS_MESSAGE_REMOTE_HISTORY_MESSAGE = true;\n    private static boolean IS_CHATROOM_MESSAGE_REMOTE_HISTORY_MESSAGE = true;\n\n    static final String USER_ROBOTS = \"user_robots\";\n    static final String USER_THINGS = \"user_things\";\n\n    static final String ROBOTS = \"robots\";\n    static final String THINGS = \"things\";\n\n    private static final Logger LOG = LoggerFactory.getLogger(MemoryMessagesStore.class);\n\n    private Map<Topic, StoredMessage> m_retainedStore = new HashMap<>();\n\n    private final Server m_Server;\n\n    private Map<String, TreeMap<Long, Long>> userMessages = new HashMap<>();\n\n    private Map<String, TreeMap<Long, Long>> chatroomMessages = new HashMap<>();\n\n    private ReadWriteLock mLock = new ReentrantReadWriteLock();\n    private Lock mReadLock = mLock.readLock();\n    private Lock mWriteLock = mLock.writeLock();\n\n    private Lock mUserSettingLock = new ReentrantLock();\n\n    private final DatabaseStore databaseStore;\n    private ConcurrentHashMap<String, Long> userMaxPullSeq = new ConcurrentHashMap<>();\n\n    private SensitiveFilter mSensitiveFilter;\n    private volatile long lastUpdateSensitiveTime = 0;\n\n    private ConcurrentHashMap<String, Boolean> userGlobalSlientMap = new ConcurrentHashMap<>();\n    private ConcurrentHashMap<String, Boolean> userVoipSlientMap = new ConcurrentHashMap<>();\n    private ConcurrentHashMap<String, Boolean> userPushHiddenDetail = new ConcurrentHashMap<>();\n    private ConcurrentHashMap<String, Boolean> userConvSlientMap = new ConcurrentHashMap<>();\n\n    private LinkedHashMap<String, Long> repeatFriendRequest = new LinkedHashMap<String, Long>() {\n        @Override\n        protected boolean removeEldestEntry(Map.Entry<String, Long> eldest) {\n            return System.currentTimeMillis() - eldest.getValue() > 5 * 60 * 1000;\n        }\n    };\n\n    private boolean mDisableSearch = false;\n    private boolean mDisableNicknameSearch = false;\n    private boolean mDisableUserIdSearch = false;\n    private boolean mDisableFriendRequest = false;\n    private long mFriendRequestDuration = 7 * 24 * 60 * 60 * 1000;\n    private long mFriendRejectDuration = 30 * 24 * 60 * 60 * 1000;\n    private long mFriendRequestExpiration = 7 * 24 * 60 * 60 * 1000;\n    private RateLimiter mFriendRateLimiter;\n    private RateLimiter mFriendSearchEmpthMobileRateLimiter;\n    private RateLimiter mFriendSearchRateLimiter;\n    private boolean mFriendRobotAutoAccept = true;\n\n    private long mPushExpiredTimes = 604800000L;\n    private Set<Integer> mForcePushTypes = new HashSet<>();\n\n    private boolean mMultiPlatformNotification = false;\n    private boolean mMobileDefaultSilentWhenPCOnline = true;\n    private boolean mDisableStrangerChat = false;\n    private Set<String> mAllowStrangerChatSet = new HashSet<>();\n    private Set<Integer> mAllowStrangerLineSet = new HashSet<>();\n    private boolean mDisableStrangerAddGroup = false;\n    private boolean mGroupAllowPartSuccess = false;\n\n    private boolean mIDUseUUID = true;\n    private boolean mSensitiveOnlyMessage = true;\n    private Set<String> mClientSignatureSet = new HashSet<>();\n    private boolean mRejectEmptySignature = true;\n\n    private long mChatroomParticipantIdleTime = 900000;\n    private boolean mChatroomRejoinWhenActive = true;\n    private boolean mChatroomCreateWhenNotExist = true;\n    private boolean mChatroomKickoffOtherPlatform = true;\n\n    private List<Integer> mForbiddenClientSendTypes = new ArrayList<>();\n    private List<Integer> mBlackListExceptionTypes = new ArrayList<>();\n    private List<Integer> mGroupMuteExceptionTypes = new ArrayList<>();\n    private List<Integer> mGlobalMuteExceptionTypes = new ArrayList<>();\n\n    private long mRecallTimeLimit = 300;\n    private boolean mDisableGroupManagerRecall = false;\n    private String mGroupInfoUpdateCallback;\n    private String mGroupMemberUpdateCallback;\n    private String mRelationUpdateCallback;\n    private String mUserInfoUpdateCallback;\n    private String mChannelInfoUpdateCallback;\n    private String mChatroomInfoUpdateCallback;\n    private String mChatroomMemberUpdateCallback;\n    private boolean mGroupAllowOwnerRecallSelfMsg = false;\n    private boolean mGroupAllowManagerRecallSelfMsg = false;\n    private boolean mGroupAllowClientCustomOperationNotification;\n    private boolean mGroupAllowRobotCustomOperationNotification;\n    private int mGroupVisibleQuitKickoffNotification;\n    private int mGroupForbiddenClientOperation;\n    private int mSyncDataPartSize = 0;\n    private boolean keepDisplayNameWhenDestroyUser = true;\n    private boolean keepFullInfoWhenDestroyUser = false;\n    private boolean keepMobileWhenDestroyUser = false;\n    private boolean keepMessagesWhenDestroyUser = false;\n\n    private String mRecallForwardUrl = null;\n\n    private boolean mBroadcastTargetFromUserTable = false;\n\n    private boolean mForwardMessageWithClientInfo = false;\n    private boolean mForwardMessageWithSenderInfo = false;\n    private boolean mForwardMessageWithTargetInfo = false;\n\n    private boolean mRobotCallbackWithClientInfo = false;\n    private boolean mRobotCallbackWithSenderInfo = false;\n    private boolean mRobotCallbackWithTargetInfo = false;\n    private boolean mRobotMentionExternalRobot = false;\n    private int mRobotGetUserInfoMask = 0;\n\n    private boolean mChannelCallbackWithClientInfo = false;\n    private boolean mChannelCallbackWithSenderInfo = false;\n    private boolean mChannelCallbackWithTargetInfo = false;\n    private boolean mChannelNewCallbackFeature = true;\n\n    private Set<Integer> mUserHideProperties = new HashSet<>();\n\n    MemoryMessagesStore(Server server, DatabaseStore databaseStore) {\n        m_Server = server;\n        this.databaseStore = databaseStore;\n\n        IS_MESSAGE_ROAMING = \"1\".equals(m_Server.getConfig().getProperty(MESSAGE_ROAMING));\n        try {\n            msgCompensateTimeLimit = Long.parseLong(m_Server.getConfig().getProperty(MESSAGE_Compensate_Time_Limit, \"300000\"));\n        } catch (NumberFormatException e) {\n\n        }\n        IS_MESSAGE_REMOTE_HISTORY_MESSAGE = \"1\".equals(m_Server.getConfig().getProperty(MESSAGE_Remote_History_Message));\n        IS_CHATROOM_MESSAGE_REMOTE_HISTORY_MESSAGE = \"1\".equals(m_Server.getConfig().getProperty(MESSAGE_Remote_Chatroom_History_Message, \"1\"));\n        Constants.MAX_MESSAGE_QUEUE = Integer.parseInt(m_Server.getConfig().getProperty(MESSAGE_Max_Queue));\n\n        try {\n            String signatureList = m_Server.getConfig().getProperty(BrokerConstants.CONNECT_CLIENT_SIGNATURE_LIST);\n            if(!StringUtil.isNullOrEmptyAfterTrim(signatureList)) {\n                signatureList = signatureList.replace(\"，\", \",\");\n                for (String s : signatureList.split(\",\")) {\n                    mClientSignatureSet.add(s.trim());\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        try {\n            if(!mClientSignatureSet.isEmpty()) {\n                mRejectEmptySignature = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.CONNECT_REJECT_EMPTY_SIGNATURE, \"true\"));\n            } else {\n                mRejectEmptySignature = false;\n            }\n        } catch (Exception e) {\n        }\n\n        try {\n            mDisableStrangerChat = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.MESSAGE_Disable_Stranger_Chat));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            printMissConfigLog(MESSAGE_Disable_Stranger_Chat, mDisableStrangerChat + \"\");\n        }\n\n        try {\n            String allowStrangerList = m_Server.getConfig().getProperty(BrokerConstants.MESSAGE_Allow_Stranger_Chat_List);\n            if(!StringUtil.isNullOrEmptyAfterTrim(allowStrangerList)) {\n                allowStrangerList = allowStrangerList.replace(\"，\", \",\");\n                for (String s : allowStrangerList.split(\",\")) {\n                    mAllowStrangerChatSet.add(s.trim());\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        try {\n            String allowStrangerList = m_Server.getConfig().getProperty(BrokerConstants.MESSAGE_Allow_Stranger_Line);\n            if(!StringUtil.isNullOrEmptyAfterTrim(allowStrangerList)) {\n                allowStrangerList = allowStrangerList.replace(\"，\", \",\");\n                for (String s : allowStrangerList.split(\",\")) {\n                    mAllowStrangerLineSet.add(Integer.parseInt(s.trim()));\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        try {\n            String forcePushTypes = m_Server.getConfig().getProperty(BrokerConstants.MESSAGE_Force_Push_Types);\n            if(!StringUtil.isNullOrEmptyAfterTrim(forcePushTypes)) {\n                forcePushTypes = forcePushTypes.replace(\"，\", \",\");\n                for (String s : forcePushTypes.split(\",\")) {\n                    int type = Integer.parseInt(s.trim());\n                    if(type > 0) {\n                        mForcePushTypes.add(type);\n                    }\n                }\n            }\n        } catch (Exception e) {\n        }\n\n        try {\n            mMultiPlatformNotification = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.SERVER_MULTI_PLATFROM_NOTIFICATION, \"false\"));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            printMissConfigLog(SERVER_MULTI_PLATFROM_NOTIFICATION, mMultiPlatformNotification + \"\");\n        }\n\n        try {\n            mMobileDefaultSilentWhenPCOnline = Boolean.parseBoolean(m_Server.getConfig().getProperty(SERVER_MOBILE_DEFAULT_SILENT_WHEN_PC_ONLINE, \"true\"));\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        try {\n            mDisableSearch = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Disable_Search));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            printMissConfigLog(FRIEND_Disable_Search, mDisableSearch + \"\");\n        }\n        try {\n            mDisableNicknameSearch = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Disable_NickName_Search));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            printMissConfigLog(FRIEND_Disable_NickName_Search, mDisableNicknameSearch + \"\");\n        }\n        try {\n            mDisableUserIdSearch = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Disable_UserId_Search, \"false\"));\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mDisableFriendRequest = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Disable_Friend_Request));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            printMissConfigLog(FRIEND_Disable_Friend_Request, mDisableFriendRequest + \"\");\n        }\n\n        try {\n            mFriendRequestDuration = Long.parseLong(m_Server.getConfig().getProperty(FRIEND_Repeat_Request_Duration));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            printMissConfigLog(FRIEND_Repeat_Request_Duration, mFriendRequestDuration + \"\");\n        }\n\n        try {\n            mFriendRejectDuration = Long.parseLong(m_Server.getConfig().getProperty(FRIEND_Reject_Request_Duration));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            printMissConfigLog(FRIEND_Reject_Request_Duration, mFriendRejectDuration + \"\");\n        }\n\n        try {\n            mFriendRequestExpiration = Long.parseLong(m_Server.getConfig().getProperty(FRIEND_Request_Expiration_Duration));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            printMissConfigLog(FRIEND_Request_Expiration_Duration, mFriendRequestExpiration + \"\");\n        }\n\n        try {\n            int friendRequestRateLimit = Integer.parseInt(m_Server.getConfig().getProperty(FRIEND_Request_Rate_Limit, \"0\"));\n            if(friendRequestRateLimit > 0) {\n                mFriendRateLimiter = new RateLimiter(86400, friendRequestRateLimit);\n            }\n        } catch (Exception e) {\n        }\n        try {\n            int rateLimit = Integer.parseInt(m_Server.getConfig().getProperty(FRIEND_Search_Mobile_Empty_Rate_Limit, \"0\"));\n            if(rateLimit > 0) {\n                mFriendSearchEmpthMobileRateLimiter = new RateLimiter(86400, rateLimit);\n            }\n        } catch (Exception e) {\n        }\n\n        try {\n            int rateLimit = Integer.parseInt(m_Server.getConfig().getProperty(FRIEND_Search_Rate_Limit, \"0\"));\n            if(rateLimit > 0) {\n                mFriendSearchRateLimiter = new RateLimiter(86400, rateLimit);\n            }\n        } catch (Exception e) {\n        }\n\n        try {\n            mFriendRobotAutoAccept = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Request_Robot_Auto_Accept, \"true\"));\n        } catch (Exception e) {\n        }\n\n        try {\n            mPushExpiredTimes = Long.parseLong(m_Server.getConfig().getProperty(BrokerConstants.MESSAGE_Push_Expired_Days, \"7\")) * 86400000L;\n            if(mPushExpiredTimes == 0) mPushExpiredTimes = Long.MAX_VALUE;\n        } catch (Exception e) {\n        }\n\n        try {\n            mChatroomRejoinWhenActive = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.CHATROOM_Rejoin_When_Active));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            printMissConfigLog(CHATROOM_Rejoin_When_Active, mChatroomRejoinWhenActive + \"\");\n        }\n\n        try {\n            mChatroomCreateWhenNotExist = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.CHATROOM_Create_When_Not_Exist));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            printMissConfigLog(CHATROOM_Create_When_Not_Exist, mChatroomCreateWhenNotExist + \"\");\n        }\n\n        try {\n            mChatroomKickoffOtherPlatform = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.CHATROOM_Kickoff_Other_Platform, \"true\"));\n        } catch (Exception e) {\n        }\n\n\n        try {\n            mChatroomParticipantIdleTime = Long.parseLong(m_Server.getConfig().getProperty(CHATROOM_Participant_Idle_Time, \"900000\"));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n            printMissConfigLog(CHATROOM_Participant_Idle_Time, mChatroomParticipantIdleTime + \"\");\n        }\n\n        try {\n            boolean disableRemoteMessageSearch = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.MESSAGES_DISABLE_REMOTE_SEARCH, \"false\"));\n            databaseStore.setDisableRemoteMessageSearch(disableRemoteMessageSearch);\n        } catch (Exception e) {\n        }\n\n        try {\n            boolean encryptMessage = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.MESSAGES_ENCRYPT_MESSAGE_CONTENT, \"false\"));\n            databaseStore.setEncryptMessage(encryptMessage);\n        } catch (Exception e) {\n        }\n\n        try {\n            mRecallTimeLimit = Long.parseLong(m_Server.getConfig().getProperty(BrokerConstants.MESSAGES_RECALL_TIME_LIMIT));\n        } catch (Exception e) {\n        }\n\n        try {\n            mDisableGroupManagerRecall = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.MESSAGES_DISABLE_GROUP_MANAGER_RECALL, \"false\"));\n        } catch (Exception e) {\n\n        }\n\n        try {\n            String strTypes = m_Server.getConfig().getProperty(BrokerConstants.MESSAGES_FORBIDDEN_CLIENT_SEND_TYPES);\n            if(!StringUtil.isNullOrEmpty(strTypes)) {\n                for (String strType:strTypes.split(\",\")) {\n                    try {\n                        int type = Integer.parseInt(strType);\n                        mForbiddenClientSendTypes.add(type);\n                    } catch (NumberFormatException e) {\n\n                    }\n                }\n            }\n        } catch (Exception e) {\n        }\n\n        try {\n            String strTypes = m_Server.getConfig().getProperty(BrokerConstants.MESSAGES_BLACKLIST_EXCEPTION_TYPES);\n            if(!StringUtil.isNullOrEmpty(strTypes)) {\n                for (String strType:strTypes.split(\",\")) {\n                    try {\n                        int type = Integer.parseInt(strType);\n                        mBlackListExceptionTypes.add(type);\n                    } catch (NumberFormatException e) {\n\n                    }\n                }\n            }\n        } catch (Exception e) {\n        }\n        try {\n            String strTypes = m_Server.getConfig().getProperty(BrokerConstants.MESSAGES_GROUP_MUTE_EXCEPTION_TYPES);\n            if(!StringUtil.isNullOrEmpty(strTypes)) {\n                for (String strType:strTypes.split(\",\")) {\n                    try {\n                        int type = Integer.parseInt(strType);\n                        mGroupMuteExceptionTypes.add(type);\n                    } catch (NumberFormatException e) {\n\n                    }\n                }\n            }\n        } catch (Exception e) {\n        }\n        try {\n            String strTypes = m_Server.getConfig().getProperty(BrokerConstants.MESSAGES_GLOBAL_MUTE_EXCEPTION_TYPES);\n            if(!StringUtil.isNullOrEmpty(strTypes)) {\n                for (String strType:strTypes.split(\",\")) {\n                    try {\n                        int type = Integer.parseInt(strType);\n                        mGlobalMuteExceptionTypes.add(type);\n                    } catch (NumberFormatException e) {\n\n                    }\n                }\n            }\n        } catch (Exception e) {\n        }\n\n        try {\n            mGroupInfoUpdateCallback = server.getConfig().getProperty(GROUP_INFO_UPDATE_CALLBACK);\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mGroupMemberUpdateCallback = server.getConfig().getProperty(GROUP_MEMBER_UPDATE_CALLBACK);\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mRelationUpdateCallback = server.getConfig().getProperty(RELATION_UPDATE_CALLBACK);\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mUserInfoUpdateCallback = server.getConfig().getProperty(USER_INFO_UPDATE_CALLBACK);\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mChannelInfoUpdateCallback = server.getConfig().getProperty(CHANNEL_INFO_UPDATE_CALLBACK);\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mChatroomInfoUpdateCallback = server.getConfig().getProperty(CHATROOM_INFO_UPDATE_CALLBACK);\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mChatroomMemberUpdateCallback = server.getConfig().getProperty(CHATROOM_MEMBER_UPDATE_CALLBACK);\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mGroupAllowOwnerRecallSelfMsg = Boolean.parseBoolean(server.getConfig().getProperty(GROUP_Allow_Owner_Recall_Self_Msg, \"true\"));\n        } catch (Exception e) {\n\n        }\n        try {\n            mGroupAllowManagerRecallSelfMsg = Boolean.parseBoolean(server.getConfig().getProperty(GROUP_Allow_Manager_Recall_Self_Msg, \"false\"));\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mGroupAllowClientCustomOperationNotification = Boolean.parseBoolean(server.getConfig().getProperty(GROUP_Allow_Client_Custom_Operation_Notification));\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mGroupAllowRobotCustomOperationNotification = Boolean.parseBoolean(server.getConfig().getProperty(GROUP_Allow_Robot_Custom_Operation_Notification));\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mGroupVisibleQuitKickoffNotification = Integer.parseInt(server.getConfig().getProperty(GROUP_Visible_Quit_Kickoff_Notification, \"0\"));\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mDisableStrangerAddGroup = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.GROUP_Disable_Stranger_Invite, \"false\"));\n        } catch (Exception e) {\n        }\n\n        try {\n            String s = server.getConfig().getProperty(GROUP_Forbidden_Client_Operation, null);\n            if(!StringUtil.isNullOrEmptyAfterTrim(s)) {\n                s = s.toLowerCase();\n                if(s.startsWith(\"0x\")) {\n                    s = s.substring(2);\n                    mGroupForbiddenClientOperation = Integer.parseInt(s, 16);\n                } else {\n                    mGroupForbiddenClientOperation = Integer.parseInt(s);\n                }\n            }\n        } catch (NumberFormatException e) {\n            LOG.error(\"Invalid group.forbidden_client_operation {}\", server.getConfig().getProperty(GROUP_Forbidden_Client_Operation, null));\n        }\n\n        try {\n            mSyncDataPartSize = Integer.parseInt(server.getConfig().getProperty(SYNC_Data_Part_Size, \"0\"));\n        } catch (Exception e) {\n\n        }\n        try {\n            keepDisplayNameWhenDestroyUser = Boolean.parseBoolean(server.getConfig().getProperty(USER_KEEP_DISPLAY_NAME_WHEN_DESTROY, \"true\"));\n        } catch (Exception e) {\n\n        }\n        try {\n            keepFullInfoWhenDestroyUser = \"true\".equals(server.getConfig().getProperty(USER_KEEP_FULL_INFO_WHEN_DESTROY));\n        } catch (Exception e) {}\n\n        try {\n            keepMobileWhenDestroyUser = \"true\".equals(server.getConfig().getProperty(USER_KEEP_MOBILE_WHEN_DESTROY));\n        } catch (Exception e) {}\n\n        try {\n            keepMessagesWhenDestroyUser = \"true\".equals(server.getConfig().getProperty(USER_KEEP_MESSAGES_WHEN_DESTROY));\n        } catch (Exception e) {}\n\n\n        try {\n            String userHideStr = server.getConfig().getProperty(USER_HIDE_PROPERTIES);\n            if(!StringUtil.isNullOrEmpty(userHideStr)) {\n                String[] proStrs = userHideStr.split(\",\");\n                for (String proStr:proStrs) {\n                    int value = Integer.parseInt(proStr);\n                    if(value > 1 && value < 9) {\n                        mUserHideProperties.add(value);\n                    }\n                }\n            }\n        } catch (NumberFormatException e) {\n            e.printStackTrace();\n        }\n\n        try {\n            mForwardMessageWithClientInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_With_Client_Info, \"false\"));\n        } catch (Exception e) {}\n        try {\n            mForwardMessageWithSenderInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_With_Sender_Info, \"false\"));\n        } catch (Exception e) {}\n        try {\n            mForwardMessageWithTargetInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.MESSAGE_Forward_With_Target_Info, \"false\"));\n        } catch (Exception e) {}\n\n        try {\n            mBroadcastTargetFromUserTable = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.BROADCAST_Target_From_User_Table, \"false\"));\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mGroupAllowPartSuccess = \"true\".equals(server.getConfig().getProperty(BrokerConstants.GROUP_ADD_MEMBER_ALLOW_PART_SUCCESS, \"false\"));\n        } catch (Exception e) {\n        }\n\n        try {\n            mRobotCallbackWithClientInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ROBOT_Callback_With_Client_Info, \"false\"));\n        } catch (Exception e) {}\n        try {\n            mRobotCallbackWithSenderInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ROBOT_Callback_With_Sender_Info, \"false\"));\n        } catch (Exception e) {}\n        try {\n            mRobotCallbackWithTargetInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ROBOT_Callback_With_Target_Info, \"false\"));\n        } catch (Exception e) {}\n        try {\n            mRobotMentionExternalRobot = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ROBOT_Mention_External_Robot, \"false\"));\n        } catch (Exception e) {}\n        try {\n            mRobotGetUserInfoMask = Integer.parseInt(server.getConfig().getProperty(BrokerConstants.ROBOT_Get_User_Info_Mask, \"0\"));\n        } catch (Exception e) {}\n\n        try {\n            mChannelCallbackWithClientInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.CHANNEL_Callback_With_Client_Info, \"false\"));\n        } catch (Exception e) {}\n        try {\n            mChannelCallbackWithSenderInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.CHANNEL_Callback_With_Sender_Info, \"false\"));\n        } catch (Exception e) {}\n        try {\n            mChannelCallbackWithTargetInfo = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.CHANNEL_Callback_With_Target_Info, \"false\"));\n        } catch (Exception e) {}\n\n        try {\n            mChannelNewCallbackFeature = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.CHANNEL_New_Callback_Feature, \"true\"));\n        } catch (Exception e) {}\n\n        try {\n            mRecallForwardUrl = server.getConfig().getProperty(BrokerConstants.MESSAGE_RecallMsg_Forward_Url);\n        } catch (Exception e) {\n\n        }\n\n        try {\n            mIDUseUUID = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.ID_USE_UUID, \"false\"));\n        } catch (Exception e) {\n        }\n\n        try {\n            mSensitiveOnlyMessage = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.SENSITIVE_Only_Message, \"true\"));\n        } catch (Exception e) {\n        }\n    }\n\n    private void printMissConfigLog(String config, String defaultValue) {\n        LOG.info(\"配置文件中缺少配置项目 {}, 缺省值为 {}，可以忽略本提醒，或者更新配置项\", config, defaultValue);\n    }\n\n    @Override\n    public void initStore() {\n        updateSensitiveWord();\n    }\n\n    private Collection<WFCMessage.GroupMember> loadGroupMemberFromDB(HazelcastInstance hzInstance, String groupId) {\n        Collection<WFCMessage.GroupMember> members = databaseStore.reloadGroupMemberFromDB(hzInstance, groupId);\n        return members;\n    }\n\n    private void updateSensitiveWord() {\n        long now = System.currentTimeMillis();\n        if (now - lastUpdateSensitiveTime > 2 * 60 * 60 * 1000) {\n            synchronized (this) {\n                if (now - lastUpdateSensitiveTime > 2 * 60 * 60 * 1000) {\n                    lastUpdateSensitiveTime = now;\n                } else {\n                    return;\n                }\n            }\n            Set<String> sensitiveWords = databaseStore.getSensitiveWord();\n            mSensitiveFilter = new SensitiveFilter(sensitiveWords);\n        }\n    }\n\n    @Override\n    public DatabaseStore getDatabaseStore() {\n        return databaseStore;\n    }\n\n    @Override\n    public WFCMessage.Message storeMessage(String fromUser, String fromClientId, WFCMessage.Message message) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<Long, MessageBundle> mIMap = hzInstance.getMap(MESSAGES_MAP);\n\n\n        MessageBundle messageBundle = new MessageBundle(message.getMessageId(), fromUser, fromClientId, message);\n        if (message.getContent().getPersistFlag() ==  Transparent) {\n            mIMap.put(message.getMessageId(), messageBundle, 10, TimeUnit.SECONDS);\n        } else {\n            mIMap.put(message.getMessageId(), messageBundle, 7, TimeUnit.DAYS);\n        }\n\n        return message;\n    }\n\n    @Override\n    public void storeSensitiveMessage(WFCMessage.Message message) {\n        databaseStore.persistSensitiveMessage(message);\n    }\n\n\n    @Override\n    public int getNotifyReceivers(String fromUser, WFCMessage.Message.Builder messageBuilder, Set<String> notifyReceivers, ProtoConstants.RequestSourceType requestSourceType) {\n        WFCMessage.Message message = messageBuilder.build();\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        int type = message.getConversation().getType();\n        int pullType = ProtoConstants.PullType.Pull_Normal;\n\n        if (type == ProtoConstants.ConversationType.ConversationType_Private) {\n            if(mRobotMentionExternalRobot && message.getConversation().getTarget().contains(\"|\")) {\n                String[] ss = message.getConversation().getTarget().split(\"\\\\|\");\n                notifyReceivers.add(ss[0]);\n                notifyReceivers.add(ss[1]);\n                if(!message.getToList().isEmpty()) {\n                    notifyReceivers.addAll(message.getToList());\n                } else if(!StringUtil.isNullOrEmpty(message.getToUser())) {\n                    notifyReceivers.add(message.getToUser());\n                }\n            } else {\n                notifyReceivers.add(fromUser);\n                if (message.getToCount() > 0) {\n                    if (message.getToList().contains(message.getConversation().getTarget())) {\n                        notifyReceivers.add(message.getConversation().getTarget());\n                    }\n                } else {\n                    notifyReceivers.add(message.getConversation().getTarget());\n                }\n            }\n            if (mRobotMentionExternalRobot && message.getContent().getMentionedTargetCount() > 0) {\n                for (String mentioned : message.getContent().getMentionedTargetList()) {\n                    if (!notifyReceivers.contains(mentioned)) {\n                        WFCMessage.User user = getUserInfo(mentioned);\n                        if(user != null && user.getType() == ProtoConstants.UserType.UserType_Robot) {\n                            notifyReceivers.add(mentioned);\n                        }\n                    }\n                }\n            }\n            pullType = ProtoConstants.PullType.Pull_Normal;\n        } else if (type == ProtoConstants.ConversationType.ConversationType_Group) {\n            notifyReceivers.add(fromUser);\n            if (!StringUtil.isNullOrEmpty(message.getToUser())) {\n                notifyReceivers.add(message.getToUser());\n            } else if(message.getToList()!=null && !message.getToList().isEmpty()) {\n                MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n                Collection<WFCMessage.GroupMember> members = groupMembers.get(message.getConversation().getTarget());\n                if (members == null || members.size() == 0) {\n                    members = loadGroupMemberFromDB(hzInstance, message.getConversation().getTarget());\n                }\n                for (WFCMessage.GroupMember member : members) {\n                    if (member.getType() != GroupMemberType_Removed && message.getToList().contains(member.getMemberId())) {\n                        notifyReceivers.add(member.getMemberId());\n                    }\n                }\n            } else {\n                MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n                Collection<WFCMessage.GroupMember> members = groupMembers.get(message.getConversation().getTarget());\n                if (members == null || members.size() == 0) {\n                    members = loadGroupMemberFromDB(hzInstance, message.getConversation().getTarget());\n                }\n                for (WFCMessage.GroupMember member : members) {\n                    if (member.getType() != GroupMemberType_Removed) {\n                        notifyReceivers.add(member.getMemberId());\n                    }\n                }\n            }\n            if (mRobotMentionExternalRobot && message.getContent().getMentionedTargetCount() > 0) {\n                for (String mentioned : message.getContent().getMentionedTargetList()) {\n                    if (!notifyReceivers.contains(mentioned)) {\n                        WFCMessage.User user = getUserInfo(mentioned);\n                        if(user != null && user.getType() == ProtoConstants.UserType.UserType_Robot) {\n                            notifyReceivers.add(mentioned);\n                        }\n                    }\n                }\n            }\n            pullType = ProtoConstants.PullType.Pull_Normal;\n        } else if (type == ProtoConstants.ConversationType.ConversationType_ChatRoom) {\n            boolean isDirect = !StringUtil.isNullOrEmpty(message.getToUser()) || !message.getToList().isEmpty();\n            Collection<UserClientEntry> entries = getChatroomMembers(message.getConversation().getTarget());\n            for (UserClientEntry entry : entries) {\n                if (isDirect) {\n                    if (entry.userId.equals(message.getToUser())) {\n                        notifyReceivers.add(message.getToUser());\n                        break;\n                    }\n                    if (message.getToList().contains(entry.userId)) {\n                        notifyReceivers.add(entry.userId);\n                    }\n                } else {\n                    notifyReceivers.add(entry.userId);\n                }\n            }\n\n            pullType = ProtoConstants.PullType.Pull_ChatRoom;\n        } else if(type == ProtoConstants.ConversationType.ConversationType_Channel) {\n            WFCMessage.ChannelInfo channelInfo = getChannelInfo(message.getConversation().getTarget());\n            if (channelInfo != null) {\n                if (channelInfo.getOwner().equals(fromUser)) {\n                    if(requestSourceType == ProtoConstants.RequestSourceType.Request_From_Channel\n                        && channelInfo.getAutomatic() != 0 && !isChannelNewCallbackFeature()) {\n                        LOG.info(\"Channel api message not send to the owner when automatic\");\n                    } else {\n                        notifyReceivers.add(fromUser);\n                    }\n\n                    if((channelInfo.getStatus() & ProtoConstants.ChannelState.Channel_State_Mask_Global) > 0) {\n                        if((message.getToList() != null && !message.getToList().isEmpty())) {\n                            notifyReceivers.addAll(message.getToList());\n                        } else {\n                            notifyReceivers.addAll(getAllEnds());\n                        }\n                    } else {\n                        Collection<String> listeners = getChannelListener(message.getConversation().getTarget());\n                        if (!StringUtil.isNullOrEmpty(message.getToUser())) {\n                            if (listeners.contains(message.getToUser()) || (channelInfo.getStatus() & ProtoConstants.ChannelState.Channel_State_Mask_Message_Unsubscribed) > 0) {\n                                notifyReceivers.add(message.getToUser());\n                            }\n                        } else if (message.getToList() != null && !message.getToList().isEmpty()) {\n                            for (String to : message.getToList()) {\n                                if (listeners.contains(to) || (channelInfo.getStatus() & ProtoConstants.ChannelState.Channel_State_Mask_Message_Unsubscribed) > 0) {\n                                    notifyReceivers.add(to);\n                                }\n                            }\n                        } else {\n                            notifyReceivers.addAll(listeners);\n                        }\n                    }\n                } else {\n                    notifyReceivers.add(fromUser);\n                    if (channelInfo.getAutomatic() == 0 || isChannelNewCallbackFeature()) {\n                        notifyReceivers.add(channelInfo.getOwner());\n                    } else {\n                        LOG.info(\"Channel api message not send to the owner when automatic\");\n                    }\n                }\n            } else {\n                LOG.error(\"Channel not exist\");\n            }\n        }\n//\n//        if (message.getContent().getPersistFlag() == Transparent) {\n//            notifyReceivers.remove(fromUser);\n//        }\n\n        return pullType;\n    }\n\n    private final Map<String, Integer> unreceivedMsgCount = new ConcurrentHashMap<>();\n\n    @Override\n    public void increaseUnreceivedMsgCount(String user) {\n        unreceivedMsgCount.compute(user, (s, integer) -> integer == null ? 1 : integer+1);\n    }\n\n    @Override\n    public int getUnreceivedMsgCount(String user) {\n        return unreceivedMsgCount.getOrDefault(user, 0);\n    }\n\n    @Override\n    public Set<String> getAllEnds() {\n        return databaseStore.getAllEnds(mBroadcastTargetFromUserTable);\n    }\n    @Override\n    public WFCMessage.PullMessageResult fetchMessage(String user, String exceptClientId, long fromMessageId, int pullType) {\n        WFCMessage.PullMessageResult.Builder builder = WFCMessage.PullMessageResult.newBuilder();\n\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<Long, MessageBundle> mIMap = hzInstance.getMap(MESSAGES_MAP);\n\n        MemorySessionStore.Session session = m_Server.getStore().sessionsStore().getSession(exceptClientId);\n        session.refreshLastActiveTime();\n        if (pullType != ProtoConstants.PullType.Pull_ChatRoom) {\n            unreceivedMsgCount.put(user, 0);\n        } else {\n            session.refreshLastChatroomActiveTime();\n        }\n\n        String chatroomId = null;\n        if (pullType == ProtoConstants.PullType.Pull_ChatRoom) {\n            chatroomId = (String)m_Server.getHazelcastInstance().getMap(USER_CHATROOM).get(user);\n        }\n\n\n        long head = fromMessageId;\n        long current = fromMessageId;\n\n        TreeMap<Long, Long> maps;\n\n        if (pullType != ProtoConstants.PullType.Pull_ChatRoom) {\n            maps = userMessages.get(user);\n            if (maps == null) {\n                loadUserMessages(user);\n            }\n            maps = userMessages.get(user);\n        } else {\n            maps = chatroomMessages.get(user);\n            if (maps == null) {\n                mWriteLock.lock();\n                try {\n                    maps = chatroomMessages.get(user);\n                    if (maps == null) {\n                        maps = new TreeMap<>();\n                        chatroomMessages.put(user, maps);\n                    }\n                } finally {\n                    mWriteLock.unlock();\n                }\n            }\n        }\n\n        if(fromMessageId == 1) { //lite mode\n            if(maps == null || maps.isEmpty()) {\n                head = 0;\n            } else {\n                head = maps.lastKey();\n            }\n            builder.setCurrent(head);\n            builder.setHead(head);\n            return builder.build();\n        }\n\n        mReadLock.lock();\n        int size = 0;\n        try {\n            if (pullType != ProtoConstants.PullType.Pull_ChatRoom) {\n                userMaxPullSeq.compute(user, (s, aLong) -> {\n                    if (aLong == null || aLong < fromMessageId) {\n                        return fromMessageId;\n                    } else {\n                        return aLong;\n                    }\n                });\n            }\n\n            boolean noRoaming = false;\n            if (pullType == ProtoConstants.PullType.Pull_Normal && fromMessageId == 0) {\n                if(!IS_MESSAGE_ROAMING) {\n                    noRoaming = true;\n                }\n                session.setPullHistoryMsg(true);\n            }\n\n            long previousCurrent;\n            while (true) {\n                Map.Entry<Long, Long> entry = maps.higherEntry(current);\n                if (entry == null) {\n                    break;\n                }\n                previousCurrent = current;\n                current = entry.getKey();\n                long targetMessageId = entry.getValue();\n\n                MessageBundle bundle = mIMap.get(targetMessageId);\n\n                if (bundle != null) {\n                    if (exceptClientId == null || session.isPullHistoryMsg() || !exceptClientId.equals(bundle.getFromClientId()) || !user.equals(bundle.getFromUser())) {\n\n                        if (pullType == ProtoConstants.PullType.Pull_ChatRoom) {\n                            if (!bundle.getMessage().getConversation().getTarget().equals(chatroomId)) {\n                                continue;\n                            }\n                        }\n\n                        if (noRoaming && (System.currentTimeMillis() - bundle.getMessage().getServerTimestamp() > msgCompensateTimeLimit)) {\n                            continue;\n                        }\n\n                        if (bundle.getMessage().getContent().getExpireDuration() > 0) {\n                            if (System.currentTimeMillis() > bundle.getMessage().getServerTimestamp() + bundle.getMessage().getContent().getExpireDuration()* 1000L) {\n                                continue;\n                            }\n                        }\n\n                        size += bundle.getMessage().getSerializedSize();\n                        if (size >= 512 * 1024) { //3M\n                            if(builder.getMessageCount() == 0){\n                                builder.addMessage(bundle.getMessage());\n                            } else {\n                                current = previousCurrent;\n                            }\n                            break;\n                        }\n                        builder.addMessage(bundle.getMessage());\n                    }\n                }\n            }\n\n            Map.Entry<Long, Long> lastEntry = maps.lastEntry();\n            if (lastEntry != null) {\n                head = lastEntry.getKey();\n            }\n            if (pullType == ProtoConstants.PullType.Pull_Normal && current == head) {\n                session.setPullHistoryMsg(false);\n            }\n        } finally {\n            mReadLock.unlock();\n        }\n\n        if(current == 0) {\n            current = 2;\n            head = 2;\n        }\n        builder.setCurrent(current);\n        builder.setHead(head);\n        return builder.build();\n    }\n\n    @Override\n    public WFCMessage.PullMessageResult loadRemoteMessages(String user, WFCMessage.Conversation conversation, long beforeUid, int count, Collection<Integer> contentTypes) {\n        WFCMessage.PullMessageResult.Builder builder = WFCMessage.PullMessageResult.newBuilder();\n        List<WFCMessage.Message> messages;\n        boolean loadMessage = IS_MESSAGE_REMOTE_HISTORY_MESSAGE;\n        if(conversation.getType() == ProtoConstants.ConversationType.ConversationType_ChatRoom) {\n            loadMessage = IS_CHATROOM_MESSAGE_REMOTE_HISTORY_MESSAGE;\n        }\n\n        String channelOwner = null;\n        if(conversation.getType() == ProtoConstants.ConversationType.ConversationType_Channel) {\n            IMap<String, WFCMessage.ChannelInfo> mIMap = m_Server.getHazelcastInstance().getMap(CHANNELS);\n            WFCMessage.ChannelInfo info = mIMap.get(conversation.getTarget());\n            if(info == null)  {\n                loadMessage = false;\n            } else {\n                channelOwner = info.getOwner();\n            }\n        }\n\n        if (loadMessage) {\n            messages = databaseStore.loadRemoteMessages(user, conversation, beforeUid, count, contentTypes, channelOwner);\n        } else {\n            messages = new ArrayList<>();\n        }\n\n        builder.setCurrent(0).setHead(0);\n        if(messages != null) {\n            builder.addAllMessage(messages);\n        }\n\n        return builder.build();\n    }\n\n    public void clearChatroomMembers(String chatroomId) {\n        MultiMap<String, UserClientEntry> chatroomMembers = m_Server.getHazelcastInstance().getMultiMap(CHATROOM_MEMBER_IDS);\n        IMap<String, String> userChatroomMap = m_Server.getHazelcastInstance().getMap(USER_CHATROOM);\n        chatroomMembers.get(chatroomId).forEach(userClientEntry -> {\n            userChatroomMap.remove(userClientEntry.userId);\n        });\n        chatroomMembers.remove(chatroomId);\n    }\n\n    @Override\n    public Collection<UserClientEntry> getChatroomMembers(String chatroomId) {\n        MultiMap<String, UserClientEntry> chatroomMembers = m_Server.getHazelcastInstance().getMultiMap(CHATROOM_MEMBER_IDS);\n        Collection<UserClientEntry> members = chatroomMembers.get(chatroomId);\n        return members;\n    }\n\n    @Override\n    public OutputUserChatroom getUserChatroom(String userId) {\n        String chatroomId = (String) m_Server.getHazelcastInstance().getMap(USER_CHATROOM).get(userId);\n        if(chatroomId != null) {\n            MultiMap<String, UserClientEntry> chatroomMembers = m_Server.getHazelcastInstance().getMultiMap(CHATROOM_MEMBER_IDS);\n            for (UserClientEntry userClientEntry : chatroomMembers.get(chatroomId)) {\n                if(userClientEntry.userId.equals(userId)) {\n                    OutputUserChatroom outputUserChatroom = new OutputUserChatroom();\n                    outputUserChatroom.userId = userId;\n                    outputUserChatroom.chatroomId = chatroomId;\n                    outputUserChatroom.clientId = userClientEntry.clientId;\n                    MemorySessionStore.Session session = m_Server.getStore().sessionsStore().getSession(userClientEntry.clientId);\n                    if(session != null) {\n                        outputUserChatroom.platform = session.getPlatform();\n                    }\n                    return outputUserChatroom;\n                }\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public WFCMessage.PullMessageResult fetchChatroomMessage(String fromUser, String chatroomId, String exceptClientId, long fromMessageId) {\n        WFCMessage.PullMessageResult.Builder builder = WFCMessage.PullMessageResult.newBuilder();\n\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<Long, MessageBundle> mIMap = hzInstance.getMap(MESSAGES_MAP);\n\n\n        long head = fromMessageId;\n        long current = fromMessageId;\n\n        TreeMap<Long, Long> maps = chatroomMessages.get(chatroomId);\n        if (maps == null) {\n            mWriteLock.lock();\n            try {\n                maps = chatroomMessages.get(chatroomId);\n                if (maps == null) {\n                    maps = new TreeMap<>();\n                    chatroomMessages.put(chatroomId, maps);\n                }\n            } finally {\n                mWriteLock.unlock();\n            }\n        }\n\n        mReadLock.lock();\n        int size = 0;\n        try {\n            maps = chatroomMessages.get(chatroomId);\n\n            while (true) {\n                Map.Entry<Long, Long> entry = maps.higherEntry(current);\n                if (entry == null) {\n                    break;\n                }\n                current = entry.getKey();\n                long targetMessageId = entry.getValue();\n\n                MessageBundle bundle = mIMap.get(targetMessageId);\n                if (bundle != null) {\n                    if (exceptClientId == null || !exceptClientId.equals(bundle.getFromClientId()) || !fromUser.equals(bundle.getFromUser())) {\n                        if (bundle.getMessage().getContent().getExpireDuration() > 0) {\n                            if (System.currentTimeMillis() > bundle.getMessage().getServerTimestamp() + bundle.getMessage().getContent().getExpireDuration() * 1000) {\n                                continue;\n                            }\n                        }\n\n                        size += bundle.getMessage().getSerializedSize();\n                        if (size >= 3 * 1024 * 1024) { //3M\n                            break;\n                        }\n                        builder.addMessage(bundle.getMessage());\n                    }\n                }\n            }\n\n            Map.Entry<Long, Long> lastEntry = maps.lastEntry();\n            if (lastEntry != null) {\n                head = lastEntry.getKey();\n            }\n        } finally {\n            mReadLock.unlock();\n        }\n\n        builder.setCurrent(current);\n        builder.setHead(head);\n        return builder.build();\n    }\n\n    @Override\n    public long insertUserMessages(String sender, int conversationType, String target, int line, int messageContentType, String user, long messageId, boolean directing) {\n        // messageId是全局的，messageSeq是跟个人相关的，理论上messageId的增长数度远远大于seq。\n        // 考虑到一种情况，当服务器发生变化，用户发生迁移后，messageSeq还需要保持有序。 要么把Seq持久化，要么在迁移后Seq取一个肯定比以前更大的数字（这个数字就是messageId）\n        // 这里选择使用后面一种情况\n        long messageSeq = 0;\n\n        if (conversationType == ProtoConstants.ConversationType.ConversationType_ChatRoom) {\n            return insertChatroomMessages(target, line, messageId);\n        }\n\n\n        mWriteLock.lock();\n        try {\n            TreeMap<Long, Long> maps = userMessages.get(user);\n            if (maps == null) {\n                maps = databaseStore.reloadUserMessageMaps(user);\n                userMessages.put(user, maps);\n            }\n\n            Map.Entry<Long, Long> lastEntry = maps.lastEntry();\n            if (lastEntry != null) {\n                messageSeq = (lastEntry.getKey() + 1);\n            }\n            Long maxPullSeq = userMaxPullSeq.get(user);\n            if (maxPullSeq != null && maxPullSeq > messageSeq) {\n                messageSeq = maxPullSeq + 1;\n            }\n\n            if (messageSeq < messageId) {\n                messageSeq = messageId;\n            }\n\n            maps.put(messageSeq, messageId);\n            if (maps.size() > MAX_MESSAGE_QUEUE) {\n                maps.remove(maps.firstKey());\n            }\n        } finally {\n            mWriteLock.unlock();\n        }\n\n        databaseStore.persistUserMessage(user, sender, messageId, messageSeq, conversationType, target, line, directing, messageContentType);\n        return messageSeq;\n    }\n\n    @Override\n    public Collection<String> getChatroomMemberClient(String userId) {\n        String chatroomId = (String)m_Server.getHazelcastInstance().getMap(USER_CHATROOM).get(userId);\n        if (StringUtil.isNullOrEmpty(chatroomId)) {\n            return new HashSet<>();\n        }\n        MultiMap<String, UserClientEntry> chatroomMembers = m_Server.getHazelcastInstance().getMultiMap(CHATROOM_MEMBER_IDS);\n        if (chatroomMembers == null) {\n            return new HashSet<>();\n        }\n\n        Collection<UserClientEntry> entries = chatroomMembers.get(chatroomId);\n\n        HashSet<String> clientIds = new HashSet<>();\n        if (entries == null) {\n            return clientIds;\n        }\n        for (UserClientEntry entry : entries\n             ) {\n            clientIds.add(entry.clientId);\n        }\n        return clientIds;\n    }\n\n    @Override\n    public boolean checkUserClientInChatroom(String user, String clientId, String chatroomId) {\n        MemorySessionStore.Session session = m_Server.getStore().sessionsStore().getSession(clientId);\n\n        String existChatroomId = (String)m_Server.getHazelcastInstance().getMap(USER_CHATROOM).get(user);\n        if (chatroomId == null) {\n            if (existChatroomId == null) {\n                return false;\n            } else {\n                chatroomId = existChatroomId;\n            }\n        }\n\n        if (StringUtil.isNullOrEmpty(existChatroomId) || !existChatroomId.equals(chatroomId)) {\n            if (mChatroomRejoinWhenActive) {\n                if (!StringUtil.isNullOrEmpty(existChatroomId)) {\n                    handleQuitChatroom(user, clientId, existChatroomId);\n                }\n                handleJoinChatroom(user, clientId, chatroomId);\n            } else {\n                return false;\n            }\n        }\n\n        if (!mChatroomRejoinWhenActive && !checkChatroomParticipantIdelTime(session)) {\n            handleQuitChatroom(user, clientId, chatroomId);\n            return false;\n        }\n\n        MultiMap<String, UserClientEntry> chatroomMembers = m_Server.getHazelcastInstance().getMultiMap(CHATROOM_MEMBER_IDS);\n        if (chatroomMembers == null) {\n            return false;\n        }\n\n        Collection<UserClientEntry> entries = chatroomMembers.get(existChatroomId);\n        if (entries == null) {\n            return false;\n        }\n\n        for (UserClientEntry entry : entries\n            ) {\n            if (entry.clientId.equals(clientId)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public long insertChatroomMessages(String target, int line, long messageId) {\n        // messageId是全局的，messageSeq是跟个人相关的，理论上messageId的增长数度远远大于seq。\n        // 考虑到一种情况，当服务器发生变化，用户发生迁移后，messageSeq还需要保持有序。 要么把Seq持久化，要么在迁移后Seq取一个肯定比以前更大的数字（这个数字就是messageId）\n        // 这里选择使用后面一种情况\n        long messageSeq = 0;\n\n        mWriteLock.lock();\n        try {\n            TreeMap<Long, Long> maps = chatroomMessages.get(target);\n            if (maps == null) {\n                maps = new TreeMap<>();\n                chatroomMessages.put(target, maps);\n            }\n\n            Map.Entry<Long, Long> lastEntry = maps.lastEntry();\n            if (lastEntry != null) {\n                messageSeq = (lastEntry.getKey() + 1);\n            }\n\n\n            if (messageSeq == 0) {\n                messageSeq = messageId;\n            }\n\n            maps.put(messageSeq, messageId);\n            if (maps.size() > MAX_CHATROOM_MESSAGE_QUEUE) {\n                maps.remove(maps.firstKey());\n            }\n        } finally {\n            mWriteLock.unlock();\n        }\n\n        return messageSeq;\n    }\n\n    @Override\n    public ErrorCode canAddGroupMembers(String fromUser, List<WFCMessage.GroupMember> memberList, Map<String, Integer> failedMembers) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n        IMap<String, WFCMessage.User> mUserMap = hzInstance.getMap(USERS);\n\n        WFCMessage.User operator = mUserMap.get(fromUser);\n        if(operator != null && operator.getType() > 1) {\n            return ErrorCode.ERROR_CODE_SUCCESS;\n        }\n\n        if (mDisableStrangerAddGroup) {\n            for (WFCMessage.GroupMember groupMember : memberList) {\n                String targetUser = groupMember.getMemberId();\n                if(fromUser.equals(targetUser)) {\n                    continue;\n                }\n\n                Collection<FriendData> friendDatas = friendsMap.get(targetUser);\n                if (friendDatas == null || friendDatas.size() == 0) {\n                    friendDatas = loadFriend(friendsMap, targetUser);\n                }\n\n                boolean allow = false;\n                for (FriendData friendData : friendDatas) {\n                    if (friendData.getFriendUid().equals(fromUser)) {\n                        if (friendData.getBlacked() == 1) {\n                            LOG.error(\"Add group member failure, because inviter {} is blocked by invitee {}\", fromUser, targetUser);\n                            if(isGroupAllowPartSuccess()) {\n                                failedMembers.put(targetUser, 1); //black\n                            } else {\n                                return ErrorCode.ERROR_CODE_IN_BLACK_LIST;\n                            }\n                        } else {\n                            if (friendData.getState() == 0) {\n                                allow = true;\n                            }\n                            break;\n                        }\n                    }\n                }\n                if(allow) {\n                    continue;\n                }\n\n                //在禁止私聊时，是否是允许私聊的用户id\n                if(mAllowStrangerChatSet.contains(targetUser) || mAllowStrangerChatSet.contains(fromUser)) {\n                    continue;\n                }\n\n                //在禁止私聊时，允许机器人，物联网设备及管理员进行私聊。\n                WFCMessage.User target = mUserMap.get(targetUser);\n                if (target != null && target.getType() != ProtoConstants.UserType.UserType_Normal) {\n                    continue;\n                }\n\n                if(isGroupAllowPartSuccess()) {\n                    failedMembers.put(targetUser, 2);//stranger\n                } else {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n            }\n        } else {\n            for (WFCMessage.GroupMember groupMember : memberList) {\n                String targetUser = groupMember.getMemberId();\n                if(fromUser.equals(targetUser)) {\n                    continue;\n                }\n\n                Collection<FriendData> friendDatas = friendsMap.get(targetUser);\n                if (friendDatas == null || friendDatas.size() == 0) {\n                    friendDatas = loadFriend(friendsMap, targetUser);\n                }\n\n                for (FriendData friendData : friendDatas) {\n                    if (friendData.getFriendUid().equals(fromUser)) {\n                        if (friendData.getBlacked() == 1) {\n                            LOG.error(\"Add group member failure, because inviter {} is blocked by invitee {}\", fromUser, targetUser);\n                            if(isGroupAllowPartSuccess()) {\n                                failedMembers.put(targetUser, 1); //black\n                            } else {\n                                return ErrorCode.ERROR_CODE_IN_BLACK_LIST;\n                            }\n                        } else {\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public WFCMessage.GroupInfo createGroup(String fromUser, WFCMessage.GroupInfo groupInfo, List<WFCMessage.GroupMember> memberList, String memberExtra, boolean isAdmin, Map<String, Integer> failedMembers) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n\n        String groupId = null;\n        long dt = System.currentTimeMillis();\n        if (StringUtil.isNullOrEmpty(groupInfo.getTargetId())) {\n            groupId = getShortUUID();\n        } else {\n            groupId = groupInfo.getTargetId();\n        }\n\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n\n        String owner = fromUser;\n        if (isAdmin && !StringUtil.isNullOrEmpty(groupInfo.getOwner())) {\n            owner = groupInfo.getOwner();\n        }\n\n        List<WFCMessage.GroupMember> updatedMemberList = new ArrayList<>();\n        boolean hasOwnerMember = false;\n        for (WFCMessage.GroupMember member : memberList) {\n            if(failedMembers.containsKey(member.getMemberId())) {\n                continue;\n            }\n            WFCMessage.GroupMember.Builder builder = member.toBuilder();\n            builder.setUpdateDt(dt).setCreateDt(dt);\n            if (member.getMemberId().equals(owner)) {\n                builder.setType(ProtoConstants.GroupMemberType.GroupMemberType_Owner);\n                hasOwnerMember = true;\n            } else {\n                if (isAdmin) {\n                    if (member.getType() == GroupMemberType_Owner) {\n                        builder.setType(GroupMemberType_Normal);\n                        LOG.error(\"group member conflicted, group info owner is {}, and group member {} type is owner, set the member to normal member\", owner, member.getMemberId());\n                    }\n                } else {\n                    builder.setType(GroupMemberType_Normal);\n                }\n            }\n\n            if(!StringUtil.isNullOrEmpty(memberExtra)) {\n                builder.setExtra(memberExtra);\n            }\n\n            member = builder.build();\n            groupMembers.put(groupId, member);\n            updatedMemberList.add(member);\n            dt++;\n        }\n\n        if(!hasOwnerMember && !StringUtil.isNullOrEmpty(owner)) {\n            WFCMessage.GroupMember member;\n            if(!StringUtil.isNullOrEmpty(memberExtra)) {\n                member = WFCMessage.GroupMember.newBuilder().setMemberId(owner).setExtra(memberExtra).setUpdateDt(dt).setCreateDt(dt).setType(ProtoConstants.GroupMemberType.GroupMemberType_Owner).build();\n            } else {\n                member = WFCMessage.GroupMember.newBuilder().setMemberId(owner).setUpdateDt(dt).setCreateDt(dt).setType(ProtoConstants.GroupMemberType.GroupMemberType_Owner).build();\n            }\n            groupMembers.put(groupId, member);\n            updatedMemberList.add(member);\n        }\n\n        groupInfo = groupInfo.toBuilder()\n            .setTargetId(groupId)\n            .setName(groupInfo.getName())\n            .setPortrait(groupInfo.getPortrait())\n            .setType(groupInfo.getType())\n            .setExtra(groupInfo.getExtra())\n            .setUpdateDt(dt)\n            .setMemberUpdateDt(dt)\n            .setMemberCount(updatedMemberList.size())\n            .setOwner(owner)\n            .build();\n\n        mIMap.set(groupId, groupInfo);\n        databaseStore.persistGroupMember(groupId, updatedMemberList, false);\n\n        callbackGroupEvent(fromUser, groupInfo.getTargetId(), ProtoConstants.GroupUpdateEventType.Group_Event_Create, groupInfo);\n        return groupInfo;\n    }\n\n\n    private void callbackGroupEvent(String operatorId, String groupId, int type, WFCMessage.GroupInfo groupInfo) {\n        if (!StringUtil.isNullOrEmpty(mGroupInfoUpdateCallback)) {\n            GroupUpdateEvent event = new GroupUpdateEvent();\n            event.operatorId = operatorId;\n            event.groupId = groupId;\n            event.type = type;\n            PojoGroupInfo pojoGroupInfo = new PojoGroupInfo();\n            event.groupInfo = pojoGroupInfo;\n            if (groupInfo != null && groupInfo.getDeleted() == 0) {\n                pojoGroupInfo.setExtra(groupInfo.getExtra());\n                pojoGroupInfo.setName(groupInfo.getName());\n                pojoGroupInfo.setOwner(groupInfo.getOwner());\n                pojoGroupInfo.setPortrait(groupInfo.getPortrait());\n                pojoGroupInfo.setTarget_id(groupInfo.getTargetId());\n                pojoGroupInfo.setType(groupInfo.getType());\n                pojoGroupInfo.setMute(groupInfo.getMute());\n                pojoGroupInfo.setJoin_type(groupInfo.getJoinType());\n                pojoGroupInfo.setPrivate_chat(groupInfo.getPrivateChat());\n                pojoGroupInfo.setSearchable(groupInfo.getSearchable());\n                pojoGroupInfo.setMax_member_count(groupInfo.getMemberCount());\n                pojoGroupInfo.setHistory_message(groupInfo.getHistoryMessage());\n                pojoGroupInfo.setSuper_group(groupInfo.getSuperGroup()>0);\n            }\n\n            m_Server.getCallbackScheduler().execute(() -> {\n                try {\n                    HttpUtils.httpJsonPost(mGroupInfoUpdateCallback, GsonUtil.gson.toJson(event), HttpUtils.HttpPostType.POST_TYPE_Grout_Event_Callback);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n                }\n            });\n        }\n    }\n\n    private void callbackGroupMemberEvent(String operatorId, String groupId, List<String> memberIds, int type, String value) {\n        if (!StringUtil.isNullOrEmpty(mGroupMemberUpdateCallback)) {\n            GroupMemberUpdateEvent event = new GroupMemberUpdateEvent();\n            event.operatorId = operatorId;\n            event.groupId = groupId;\n            event.memberIds = memberIds;\n            event.type = type;\n            event.value = value;\n            m_Server.getCallbackScheduler().execute(() -> {\n                try {\n                    HttpUtils.httpJsonPost(mGroupMemberUpdateCallback, GsonUtil.gson.toJson(event), HttpUtils.HttpPostType.POST_TYPE_Grout_Member_Event_Callback);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n                }\n            });\n        }\n    }\n\n    private void callbackRelationEvent(String userId, String targetId, int type, String value) {\n        if (!StringUtil.isNullOrEmpty(mRelationUpdateCallback)) {\n            RelationUpdateEvent event = new RelationUpdateEvent();\n            event.userId = userId;\n            event.targetId = targetId;\n            event.type = type;\n            event.value = value;\n            m_Server.getCallbackScheduler().execute(() -> {\n                try {\n                    HttpUtils.httpJsonPost(mRelationUpdateCallback, GsonUtil.gson.toJson(event), HttpUtils.HttpPostType.POST_TYPE_User_Relation_Event_Callback);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n                }\n            });\n        }\n    }\n\n    private void callbackUserInfoEvent(WFCMessage.User user) {\n        if (!StringUtil.isNullOrEmpty(mUserInfoUpdateCallback)) {\n            m_Server.getCallbackScheduler().execute(() -> {\n                try {\n                    HttpUtils.httpJsonPost(mUserInfoUpdateCallback, GsonUtil.gson.toJson(InputOutputUserInfo.fromPbUser(user)), HttpUtils.HttpPostType.POST_TYPE_User_Info_Event_Callback);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n                }\n            });\n        }\n    }\n\n    private void callbackChannelInfoUpdateEvent(String operatorId, String channelId, int type) {\n        if (!StringUtil.isNullOrEmpty(mChannelInfoUpdateCallback)) {\n            ChannelUpdateEvent event = new ChannelUpdateEvent();\n            event.operatorId = operatorId;\n            event.channelId = channelId;\n            event.type = type;\n            m_Server.getCallbackScheduler().execute(() -> {\n                try {\n                    HttpUtils.httpJsonPost(mChannelInfoUpdateCallback, GsonUtil.gson.toJson(event), HttpUtils.HttpPostType.POST_TYPE_Channel_Info_Event_Callback);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n                }\n            });\n        }\n    }\n\n    private void callbackChatroomInfoUpdateEvent(String chatroomId, int type) {\n        if (!StringUtil.isNullOrEmpty(mChatroomInfoUpdateCallback)) {\n            ChatroomUpdateEvent event = new ChatroomUpdateEvent();\n            event.chatroomId = chatroomId;\n            event.type = type;\n            m_Server.getCallbackScheduler().execute(() -> {\n                try {\n                    HttpUtils.httpJsonPost(mChatroomInfoUpdateCallback, GsonUtil.gson.toJson(event), HttpUtils.HttpPostType.POST_TYPE_Chatroom_Info_Event_Callback);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n                }\n            });\n        }\n    }\n\n    private void callbackChatroomMemberEvent(String operatorId, String chatroomId, List<String> memberIds, int type) {\n        if (!StringUtil.isNullOrEmpty(mChatroomMemberUpdateCallback)) {\n            ChatroomMemberUpdateEvent event = new ChatroomMemberUpdateEvent();\n            event.operatorId = operatorId;\n            event.chatroomId = chatroomId;\n            event.memberIds = memberIds;\n            event.type = type;\n            m_Server.getCallbackScheduler().execute(() -> {\n                try {\n                    HttpUtils.httpJsonPost(mChatroomMemberUpdateCallback, GsonUtil.gson.toJson(event), HttpUtils.HttpPostType.POST_TYPE_Chatroom_Member_Event_Callback);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n                }\n            });\n        }\n    }\n\n    @Override\n    public ErrorCode addGroupMembers(String operator, boolean isAdmin, String groupId, List<WFCMessage.GroupMember> memberList, String extra, Map<String, Integer> failedMembers) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n\n        WFCMessage.GroupInfo groupInfo = mIMap.get(groupId);\n        if (groupInfo == null) {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n\n        int maxCount = Integer.MAX_VALUE;\n\n        if (!isAdmin) {\n            if (groupInfo.getType() == ProtoConstants.GroupType.GroupType_Organization) {\n                return ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n            boolean isMember = false;\n            boolean isManager = false;\n            WFCMessage.GroupMember gm = getGroupMember(groupId, operator);\n            if (gm != null) {\n                if (gm.getType() == GroupMemberType_Removed && !(memberList.size() == 1 && operator.equals(memberList.get(0).getMemberId()))) {\n                    return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n                } else if (gm.getType() == GroupMemberType_Silent) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n                isManager = (gm.getType() == GroupMemberType_Manager || gm.getType() == GroupMemberType_Owner);\n\n                if (gm.getType() != GroupMemberType_Removed) {\n                    isMember = true;\n                }\n            }\n\n            if (groupInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted && ((groupInfo.getOwner() == null || !groupInfo.getOwner().equals(operator)) && !isManager)) {\n                if (groupInfo.getJoinType() == 2) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                } else if (groupInfo.getJoinType() == 1) {\n                    if (memberList.size() == 1 && operator.equals(memberList.get(0).getMemberId()))\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n            }\n\n            if (!isMember && !(memberList.size() == 1 && operator.equals(memberList.get(0).getMemberId()))) {\n                return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n            }\n\n            SystemSettingPojo maxMemberSetting = databaseStore.getSystemSetting(ProtoConstants.SystemSettingType.Group_Max_Member_Count);\n            if (maxMemberSetting != null) {\n                try {\n                    maxCount = Integer.parseInt(maxMemberSetting.value);\n                } catch (NumberFormatException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n        Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);\n        if (members == null || members.size() == 0) {\n            members = loadGroupMemberFromDB(hzInstance, groupId);\n        }\n\n        ArrayList<String> existMemberIds = new ArrayList<>();\n        for (WFCMessage.GroupMember member : members) {\n            if (member.getType() != GroupMemberType_Removed) {\n                existMemberIds.add(member.getMemberId());\n            }\n        }\n\n        long updateDt = System.currentTimeMillis();\n\n        List<WFCMessage.GroupMember> tmp = new ArrayList<>();\n        int newMemberCount = 0;\n        for (WFCMessage.GroupMember member : memberList) {\n            if(failedMembers.containsKey(member.getMemberId())) {\n                continue;\n            }\n\n            if (existMemberIds.contains(member.getMemberId()) && member.getType() != GroupMemberType_Removed) {\n                if(!isAdmin)\n                    continue;\n            } else {\n                newMemberCount++;\n            }\n\n            WFCMessage.GroupMember.Builder builder = member.toBuilder();\n            builder.setUpdateDt(updateDt).setCreateDt(updateDt);\n            if (member.getMemberId().equals(groupInfo.getOwner())) {\n                builder.setType(GroupMemberType_Owner).build();\n            } else {\n                if (isAdmin) {\n                    if (member.getType() == GroupMemberType_Owner) {\n                        builder.setType(GroupMemberType_Normal);\n                        LOG.error(\"group member conflicted, group info owner is {}, and group member {} type is owner, set the member to normal member\", groupInfo.getOwner(), member.getMemberId());\n                    }\n                } else {\n                    builder.setType(GroupMemberType_Normal);\n                }\n            }\n            if(!StringUtil.isNullOrEmpty(extra)) {\n                builder.setExtra(extra);\n            }\n            member = builder.build();\n            tmp.add(member);\n            updateDt++;\n        }\n        memberList = tmp;\n\n        if (memberList.size() == 0) {\n            if (!isAdmin) {\n                if(failedMembers.isEmpty()) {\n                    return ErrorCode.ERROR_CODE_ALREADY_IN_GROUP;\n                } else {\n                    return ErrorCode.ERROR_CODE_SUCCESS;\n                }\n            } else {\n                return ErrorCode.ERROR_CODE_SUCCESS;\n            }\n        } else {\n            if (existMemberIds.size() + newMemberCount > maxCount) {\n                return ErrorCode.ERROR_CODE_GROUP_EXCEED_MAX_MEMBER_COUNT;\n            }\n        }\n\n\n        databaseStore.persistGroupMember(groupId, memberList, true);\n        databaseStore.updateGroupMemberCountDt(groupId);\n\n        groupMembers.remove(groupId);\n        mIMap.evict(groupId);\n\n        List<String> memberIds = new ArrayList<>();\n        for (WFCMessage.GroupMember member : memberList) {\n            if(failedMembers.containsKey(member.getMemberId())) {\n                continue;\n            }\n\n            if (member.getType() != GroupMemberType_Removed) {\n                memberIds.add(member.getMemberId());\n            }\n        }\n\n        callbackGroupMemberEvent(operator, groupId, memberIds, ProtoConstants.GroupMemberUpdateEventType.Group_Member_Event_Join, null);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode kickoffGroupMembers(String operator, boolean isAdmin, String groupId, List<String> memberList) {\n        removeGroupMember(groupId, memberList);\n        removeFavGroup(groupId, memberList);\n        removeGroupUserSettings(groupId, memberList);\n\n        callbackGroupMemberEvent(operator, groupId, memberList, ProtoConstants.GroupMemberUpdateEventType.Group_Member_Event_Kickoff, null);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    void removeGroupMember(String groupId, List<String> memberIds) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        databaseStore.removeGroupMember(groupId, memberIds);\n        databaseStore.updateGroupMemberCountDt(groupId);\n\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n        groupMembers.remove(groupId);\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n        mIMap.evict(groupId);\n    }\n\n    void removeFavGroup(String groupId, List<String> memberIds) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n\n        databaseStore.removeFavGroup(groupId, memberIds);\n        try {\n            mUserSettingLock.lock();\n            MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);\n            for (String member : memberIds) {\n                userSettingMap.remove(member);\n            }\n        } finally {\n            mUserSettingLock.unlock();\n        }\n\n    }\n\n    @Override\n    public ErrorCode quitGroup(String operator, String groupId, boolean admin) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n\n        WFCMessage.GroupInfo groupInfo = mIMap.get(groupId);\n        if (groupInfo == null) {\n            MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n            Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);\n            if (members == null || members.size() == 0) {\n                members = loadGroupMemberFromDB(hzInstance, groupId);\n            }\n            for (WFCMessage.GroupMember member :members) {\n                if (member.getMemberId().equals(operator)) {\n                    groupMembers.remove(groupId, member);\n                    break;\n                }\n            }\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n        if(!admin && groupInfo.getType() == ProtoConstants.GroupType.GroupType_Organization) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if (groupInfo.getType() != ProtoConstants.GroupType.GroupType_Free && groupInfo.getOwner() != null && groupInfo.getOwner().equals(operator)) {\n            MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n            Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);\n            if (members == null || members.size() == 0) {\n                members = loadGroupMemberFromDB(hzInstance, groupId);\n            }\n\n            WFCMessage.GroupMember newOwner = null;\n            for (WFCMessage.GroupMember member :members) {\n                if (!member.getMemberId().equals(operator) && member.getType() != GroupMemberType_Removed) {\n                    if(newOwner == null) {\n                        newOwner = member;\n                    } else {\n                        if(newOwner.getType() == GroupMemberType_Silent && member.getType() != GroupMemberType_Silent) {\n                            newOwner = member;\n                        } else if(newOwner.getType() != GroupMemberType_Manager && member.getType() == GroupMemberType_Manager) {\n                            newOwner = member;\n                        } else if(newOwner.getType() == member.getType()) {\n                            if(newOwner.getCreateDt() > member.getCreateDt() && member.getCreateDt() > 0) {\n                                newOwner = member;\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (newOwner == null) {\n                 return dismissGroup(operator, groupId, false);\n            }\n\n            transferGroup(operator, groupId, newOwner.getMemberId(), false);\n\n            try {\n                Thread.sleep(500);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        }\n\n        removeGroupMember(groupId, Arrays.asList(operator));\n        removeFavGroup(groupId, Arrays.asList(operator));\n        removeGroupUserSettings(groupId, Arrays.asList(operator));\n\n        callbackGroupMemberEvent(operator, groupId, Arrays.asList(operator), ProtoConstants.GroupMemberUpdateEventType.Group_Member_Event_Leave, null);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public void clearUserGroups(String userId) {\n        Set<String> groupIds = databaseStore.getUserGroupIds(userId);\n        int[] removedCount = new int[1];\n        for (String groupId : groupIds) {\n            removedCount[0] = 0;\n            ErrorCode errorCode = quitGroup(userId, groupId, true);\n            LOG.info(\"clear user {} group {} result {}\", userId, groupId, errorCode);\n        }\n    }\n\n\n    private void removeGroupUserSettings(String groupId, List<String> users) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n\n        databaseStore.removeGroupUserSettings(groupId, users);\n        try {\n            mUserSettingLock.lock();\n            MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);\n            for (String userId:users) {\n                userSettingMap.remove(userId);\n            }\n        } finally {\n            mUserSettingLock.unlock();\n        }\n    }\n\n    @Override\n    public ErrorCode dismissGroup(String operator, String groupId, boolean isAdmin) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n\n\n        WFCMessage.GroupInfo groupInfo = mIMap.get(groupId);\n        if (groupInfo == null) {\n            MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n            groupMembers.remove(groupId);\n\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n        if (!isAdmin && (groupInfo.getType() == ProtoConstants.GroupType.GroupType_Free ||\n            groupInfo.getType() == ProtoConstants.GroupType.GroupType_Organization ||\n            (groupInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted || groupInfo.getType() == ProtoConstants.GroupType.GroupType_Normal)\n                && (groupInfo.getOwner() == null || !groupInfo.getOwner().equals(operator)))) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n\n        Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);\n        if (members == null || members.size() == 0) {\n            members = loadGroupMemberFromDB(hzInstance, groupId);\n        }\n\n        groupMembers.remove(groupId);\n        mIMap.remove(groupId);\n\n        databaseStore.removeGroupMemberFromDB(groupId);\n\n        ArrayList<String> ids = new ArrayList<>();\n        if (members != null) {\n            for (WFCMessage.GroupMember member : members) {\n                ids.add(member.getMemberId());\n            }\n        }\n        removeFavGroup(groupId, ids);\n        removeGroupUserSettings(groupId, ids);\n\n        callbackGroupEvent(operator, groupId, ProtoConstants.GroupUpdateEventType.Group_Event_Destroy, groupInfo);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode modifyGroupInfo(String operator, String groupId, int modifyType, String value, boolean isAdmin) {\n\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n\n        WFCMessage.GroupInfo oldInfo = mIMap.get(groupId);\n\n        if (oldInfo == null) {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n        if (!isAdmin) {\n            if (oldInfo.getType() == ProtoConstants.GroupType.GroupType_Organization && modifyType != Modify_Group_Extra && modifyType != Modify_Group_Mute && modifyType != Modify_Group_PrivateChat) {\n                return ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n\n            WFCMessage.GroupMember gm = getGroupMember(groupId, operator);\n            if (gm == null || gm.getType() == GroupMemberType_Removed) {\n                return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n            }\n\n            if (oldInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted || oldInfo.getType() == ProtoConstants.GroupType.GroupType_Organization) {\n                boolean isAllow = false;\n                if ((oldInfo.getOwner() != null && oldInfo.getOwner().equals(operator))) {\n                    isAllow = true;\n                } else {\n                    if (gm.getType() == GroupMemberType_Manager) {\n                        isAllow = true;\n                    }\n                }\n                if (!isAllow) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n\n                if (modifyType == Modify_Group_Name && !StringUtil.isNullOrEmpty(value)) {\n                    if(!mSensitiveOnlyMessage) {\n                        Set<String> matched = handleSensitiveWord(value);\n                        if (matched != null && !matched.isEmpty()) {\n                            return ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;\n                        }\n                    }\n\n                    if(!isAllowName(value)) {\n                        return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                    }\n                }\n            }\n\n            if (oldInfo.getType() == ProtoConstants.GroupType.GroupType_Normal) {\n                if (!operator.equals(oldInfo.getOwner())) {\n                    boolean isManager = false;\n                    if (gm.getType() == GroupMemberType_Manager) {\n                        isManager = true;\n                    }\n                    if (!isManager && modifyType != Modify_Group_Name && modifyType != Modify_Group_Portrait && modifyType != Modify_Group_Extra) {\n                        return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                    }\n                }\n            }\n\n            if (oldInfo.getType() == ProtoConstants.GroupType.GroupType_Free) {\n                if (modifyType != Modify_Group_Name && modifyType != Modify_Group_Portrait && modifyType != Modify_Group_Extra) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n            }\n        }\n\n        WFCMessage.GroupInfo.Builder newInfoBuilder = oldInfo.toBuilder();\n\n        if (modifyType == Modify_Group_Name)\n            newInfoBuilder.setName(value);\n        else if(modifyType == Modify_Group_Portrait)\n            newInfoBuilder.setPortrait(value);\n        else if(modifyType == Modify_Group_Extra)\n            newInfoBuilder.setExtra(value);\n        else if(modifyType == Modify_Group_Mute)\n            newInfoBuilder.setMute(Integer.parseInt(value));\n        else if(modifyType == Modify_Group_JoinType)\n            newInfoBuilder.setJoinType(Integer.parseInt(value));\n        else if(modifyType == Modify_Group_PrivateChat)\n            newInfoBuilder.setPrivateChat(Integer.parseInt(value));\n        else if(modifyType == Modify_Group_Searchable)\n            newInfoBuilder.setSearchable(Integer.parseInt(value));\n        else if(modifyType == Modify_Group_Type) {\n            int newType = Integer.parseInt(value);\n            if(newType < 0 || newType > ProtoConstants.GroupType.GroupType_Organization) {\n                LOG.error(\"modify group type failure, invalid group type {}\", newType);\n                return ErrorCode.INVALID_PARAMETER;\n            }\n            newInfoBuilder.setType(newType);\n        }\n        else\n            return ErrorCode.INVALID_PARAMETER;\n\n\n        newInfoBuilder.setUpdateDt(System.currentTimeMillis());\n        databaseStore.persistGroupInfo(newInfoBuilder.build());\n        mIMap.evict(groupId);\n\n        if (modifyType == Modify_Group_Mute) {\n            if (newInfoBuilder.getMute() > 0) {\n                callbackGroupEvent(operator, groupId, ProtoConstants.GroupUpdateEventType.Group_Event_Mute, newInfoBuilder.build());\n            } else {\n                callbackGroupEvent(operator, groupId, ProtoConstants.GroupUpdateEventType.Group_Event_Unmute, newInfoBuilder.build());\n            }\n        } else {\n            callbackGroupEvent(operator, groupId, ProtoConstants.GroupUpdateEventType.Group_Event_Update, newInfoBuilder.build());\n        }\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode modifyGroupMemberAlias(String operator, String groupId, String alias, String memberId, boolean isAdmin) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n        WFCMessage.GroupInfo groupInfo = mIMap.get(groupId);\n        if (groupInfo == null) {\n            groupInfo = databaseStore.getPersistGroupInfo(groupId);\n            if (groupInfo != null && groupInfo.getDeleted() == 0) {\n                mIMap.set(groupId, groupInfo);\n            } else {\n                return ErrorCode.ERROR_CODE_NOT_EXIST;\n            }\n        }\n\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n        Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);\n        if (members == null || members.size() == 0) {\n            members = loadGroupMemberFromDB(hzInstance, groupId);\n        }\n\n        if (StringUtil.isNullOrEmpty(memberId)) {\n            memberId = operator;\n        } else {\n            if (!isAdmin && !operator.equals(groupInfo.getOwner())) {\n                WFCMessage.GroupMember operatorMember = null;\n                WFCMessage.GroupMember targetMember = null;\n                for (WFCMessage.GroupMember member : members) {\n                    if (member.getMemberId().equals(operator)) {\n                        operatorMember = member;\n                        if (targetMember != null) {\n                            break;\n                        }\n                    }\n                    if ((member.getMemberId().equals(memberId))) {\n                        targetMember = member;\n                        if (operatorMember != null) {\n                            break;\n                        }\n                    }\n                }\n\n                if (operatorMember == null || operatorMember.getType() == GroupMemberType_Removed) {\n                    LOG.error(\"Modify group member alias error, the operator {} is not in group\", operator);\n                    return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n                }\n\n                if (targetMember == null || targetMember.getType() == GroupMemberType_Removed) {\n                    LOG.error(\"Modify group member alias error, the member {} is not in group\", memberId);\n                    return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n                }\n\n                if (operatorMember.getType() == GroupMemberType_Manager && targetMember.getType() != GroupMemberType_Manager) {\n                    LOG.error(\"Modify group member alias error, the operator {} type is {} and the member {} type is {}\", operator, operatorMember.getType(), memberId, targetMember.getType());\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n            }\n        }\n\n        long updateDt = System.currentTimeMillis();\n\n        boolean inGroup = false;\n        for (WFCMessage.GroupMember member : members) {\n            if (member.getMemberId().equals(memberId)) {\n                groupMembers.remove(groupId, member);\n                member = member.toBuilder().setAlias(alias).setUpdateDt(updateDt).build();\n                databaseStore.persistGroupMember(groupId, Arrays.asList(member), false);\n                databaseStore.updateGroupMemberDt(groupId, updateDt);\n                groupMembers.put(groupId, member);\n\n                mIMap.set(groupId, groupInfo.toBuilder().setUpdateDt(updateDt).setMemberUpdateDt(updateDt).build());\n                inGroup = true;\n                break;\n            }\n        }\n\n        if (!inGroup) {\n            LOG.error(\"Modify group member alias error, the member {} is not in group\", memberId);\n            return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n        }\n\n        callbackGroupMemberEvent(operator, groupId, Arrays.asList(memberId), ProtoConstants.GroupMemberUpdateEventType.Group_Member_Event_Alias, alias);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode modifyGroupMemberExtra(String operator, String groupId, String extra, String memberId, boolean isAdmin) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n        WFCMessage.GroupInfo groupInfo = mIMap.get(groupId);\n        if (groupInfo == null) {\n            groupInfo = databaseStore.getPersistGroupInfo(groupId);\n            if (groupInfo != null && groupInfo.getDeleted() == 0) {\n                mIMap.set(groupId, groupInfo);\n            } else {\n                return ErrorCode.ERROR_CODE_NOT_EXIST;\n            }\n        }\n\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n        Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);\n        if (members == null || members.size() == 0) {\n            members = loadGroupMemberFromDB(hzInstance, groupId);\n        }\n\n        if (StringUtil.isNullOrEmpty(memberId)) {\n            memberId = operator;\n        } else {\n            if (!isAdmin && !operator.equals(groupInfo.getOwner())) {\n                WFCMessage.GroupMember operatorMember = null;\n                WFCMessage.GroupMember targetMember = null;\n                for (WFCMessage.GroupMember member : members) {\n                    if (member.getMemberId().equals(operator)) {\n                        operatorMember = member;\n                        if (targetMember != null) {\n                            break;\n                        }\n                    }\n                    if ((member.getMemberId().equals(memberId))) {\n                        targetMember = member;\n                        if (operatorMember != null) {\n                            break;\n                        }\n                    }\n                }\n\n                if (operatorMember == null) {\n                    LOG.error(\"Modify group member extra error, the operator {} is not in group\", operator);\n                    return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n                }\n\n                if (targetMember == null) {\n                    LOG.error(\"Modify group member extra error, the member {} is not in group\", memberId);\n                    return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n                }\n\n                if (operatorMember.getType() == GroupMemberType_Manager && targetMember.getType() != GroupMemberType_Manager) {\n                    LOG.error(\"Modify group member extra error, the operator {} type is {} and the member {} type is {}\", operator, operatorMember.getType(), memberId, targetMember.getType());\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n            }\n        }\n\n        long updateDt = System.currentTimeMillis();\n\n        boolean inGroup = false;\n        for (WFCMessage.GroupMember member : members) {\n            if (member.getMemberId().equals(memberId)) {\n                groupMembers.remove(groupId, member);\n                member = member.toBuilder().setExtra(extra).setUpdateDt(updateDt).build();\n                databaseStore.persistGroupMember(groupId, Arrays.asList(member), false);\n                databaseStore.updateGroupMemberDt(groupId, updateDt);\n                groupMembers.put(groupId, member);\n\n                mIMap.set(groupId, groupInfo.toBuilder().setUpdateDt(updateDt).setMemberUpdateDt(updateDt).build());\n                inGroup = true;\n                break;\n            }\n        }\n\n        if (!inGroup) {\n            LOG.error(\"Modify group member extra error, the member {} is not in group\", memberId);\n            return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n        }\n\n        callbackGroupMemberEvent(operator, groupId, Arrays.asList(memberId), ProtoConstants.GroupMemberUpdateEventType.Group_Member_Event_Alias, extra);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public List<WFCMessage.GroupInfo> getGroupInfos(List<WFCMessage.UserRequest> requests, String fromUser, boolean isAdmin) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n        ArrayList<WFCMessage.GroupInfo> out = new ArrayList<>();\n        for (WFCMessage.UserRequest request : requests) {\n            WFCMessage.GroupInfo groupInfo = mIMap.get(request.getUid());\n            if (groupInfo != null && groupInfo.getUpdateDt() > request.getUpdateDt()) {\n                if(!isAdmin && !StringUtil.isNullOrEmpty(fromUser) && groupInfo.getDeleted() == 0) {\n                    WFCMessage.GroupMember gm = getGroupMember(groupInfo.getTargetId(), fromUser);\n                    if((gm == null || gm.getType() == GroupMemberType_Removed) && request.getUpdateDt() > 0) {\n                        continue;\n                    }\n                    if(gm == null) {\n                        groupInfo = groupInfo.toBuilder().setMemberUpdateDt(-1).build();\n                    } else if(gm.getType() == GroupMemberType_Removed) {\n                        groupInfo = groupInfo.toBuilder().setMemberUpdateDt(-groupInfo.getMemberUpdateDt()).build();\n                    }\n                }\n                out.add(groupInfo);\n            }\n        }\n\n        return out;\n    }\n\n    @Override\n    public WFCMessage.GroupInfo getGroupInfo(String groupId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n\n        WFCMessage.GroupInfo groupInfo = mIMap.get(groupId);\n        return groupInfo;\n    }\n\n    @Override\n    public Set<String> getUserGroupIds(String userId) {\n        return databaseStore.getUserGroupIds(userId);\n    }\n\n    @Override\n    public Set<String> getUserGroupIds(String userId, List<Integer> memberTypes) {\n        return databaseStore.getUserGroupIds(userId, memberTypes);\n    }\n\n    @Override\n    public Set<String> getCommonGroupIds(String userId1, String userId2) {\n        return databaseStore.getCommonGroupIds(userId1, userId2);\n    }\n\n    @Override\n    public ErrorCode getGroupMembers(String fromUser, String groupId, long maxDt, List<WFCMessage.GroupMember> members) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n\n        WFCMessage.GroupInfo groupInfo = mIMap.get(groupId);\n        if (groupInfo == null) {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n        Collection<WFCMessage.GroupMember> memberCollection = groupMembers.get(groupId);\n        if (memberCollection == null || memberCollection.size() == 0) {\n            memberCollection = loadGroupMemberFromDB(hzInstance, groupId);\n        }\n        boolean notInGroup = true;\n        WFCMessage.GroupMember self = null;\n        for (WFCMessage.GroupMember member:memberCollection) {\n            if (member.getUpdateDt() > maxDt) {\n                members.add(member);\n            }\n            if (fromUser != null && notInGroup) {\n                if (member.getMemberId().equals(fromUser)) {\n                    if (member.getType() != GroupMemberType_Removed) {\n                        notInGroup = false;\n                    } else {\n                        self = member;\n                        break;\n                    }\n                }\n            }\n        }\n\n        //server api fromUser is null\n        if (fromUser != null && notInGroup) {\n            members.clear();\n            if (self != null) {\n                members.add(self.toBuilder().setUpdateDt(0).setType(GroupMemberType_Removed).build());\n            }\n        }\n\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public WFCMessage.GroupMember getGroupMember(String groupId, String memberId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n\n        Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);\n        if (members == null || members.size() == 0) {\n            members = loadGroupMemberFromDB(hzInstance, groupId);\n        }\n\n        if (members != null) {\n            for (WFCMessage.GroupMember gm : members) {\n                if (gm.getMemberId().equals(memberId)) {\n                    return gm;\n                }\n            }\n        }\n\n        return null;\n    }\n\n\n    @Override\n    public ErrorCode transferGroup(String operator, String groupId, String newOwner, boolean isAdmin) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n\n\n        WFCMessage.GroupInfo groupInfo = mIMap.get(groupId);\n\n        if (groupInfo == null) {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n        if (!isAdmin && (groupInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted || groupInfo.getType() == ProtoConstants.GroupType.GroupType_Normal)\n            && (groupInfo.getOwner() == null || !groupInfo.getOwner().equals(operator))) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if (!isAdmin && groupInfo.getType() == ProtoConstants.GroupType.GroupType_Organization) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        //check the new owner is in member list? is that necessary?\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n        Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);\n        if (members == null || members.size() == 0) {\n            members = loadGroupMemberFromDB(hzInstance, groupId);\n        }\n\n        boolean isNewOwnerInGroup = false;\n        for (WFCMessage.GroupMember member : members) {\n            if (member.getMemberId().equals(newOwner)) {\n                if(member.getType() != GroupMemberType_Removed) {\n                    isNewOwnerInGroup = true;\n                }\n                break;\n            }\n        }\n        if(!isNewOwnerInGroup) {\n            return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n        }\n\n        long updateDt = System.currentTimeMillis();\n        groupInfo = groupInfo.toBuilder().setOwner(newOwner).setUpdateDt(updateDt).setMemberUpdateDt(updateDt).build();\n        mIMap.set(groupId, groupInfo);\n\n        int modifyMemeberCount = 0;\n        for (WFCMessage.GroupMember member : members) {\n            if (modifyMemeberCount == 2) {\n                break;\n            }\n            if (newOwner.equals(member.getMemberId())) {\n                groupMembers.remove(groupId, member);\n                member = member.toBuilder().setType(GroupMemberType_Owner).setUpdateDt(updateDt).build();\n                databaseStore.persistGroupMember(groupId, Arrays.asList(member), false);\n                groupMembers.put(groupId, member);\n                modifyMemeberCount++;\n            } else if(member.getType() == GroupMemberType_Owner) {\n                groupMembers.remove(groupId, member);\n                member = member.toBuilder().setType(GroupMemberType_Normal).setUpdateDt(updateDt).build();\n                databaseStore.persistGroupMember(groupId, Arrays.asList(member), false);\n                groupMembers.put(groupId, member);\n                modifyMemeberCount++;\n            }\n        }\n\n        callbackGroupEvent(operator, groupId, ProtoConstants.GroupUpdateEventType.Group_Event_Transfer, groupInfo);\n\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode setGroupManager(String operator, String groupId, int type, List<String> userList, boolean isAdmin) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.GroupInfo> mIMap = hzInstance.getMap(GROUPS_MAP);\n\n\n        WFCMessage.GroupInfo groupInfo = mIMap.get(groupId);\n\n        if (groupInfo == null) {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n        if (!isAdmin && (groupInfo.getType() == ProtoConstants.GroupType.GroupType_Restricted || groupInfo.getType() == ProtoConstants.GroupType.GroupType_Normal)\n            && (groupInfo.getOwner() == null || !groupInfo.getOwner().equals(operator))) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if(userList.contains(groupInfo.getOwner())) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        long updateDt = System.currentTimeMillis();\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n        Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);\n        if (members == null || members.size() == 0) {\n            members = loadGroupMemberFromDB(hzInstance, groupId);\n        }\n        for (WFCMessage.GroupMember member : members) {\n            if (userList.contains(member.getMemberId())) {\n                groupMembers.remove(groupId, member);\n                member = member.toBuilder().setType(type == 0 ? ProtoConstants.GroupMemberType.GroupMemberType_Normal : ProtoConstants.GroupMemberType.GroupMemberType_Manager).setUpdateDt(updateDt).build();\n                databaseStore.persistGroupMember(groupId, Arrays.asList(member), false);\n                groupMembers.put(groupId, member);\n            }\n        }\n        databaseStore.persistGroupInfo(groupInfo.toBuilder().setUpdateDt(updateDt).setMemberUpdateDt(updateDt).build());\n        mIMap.evict(groupId);\n\n        callbackGroupMemberEvent(operator, groupId, userList, ProtoConstants.GroupMemberUpdateEventType.Group_Member_Event_Type_Update, (type == 0 ? ProtoConstants.GroupMemberType.GroupMemberType_Normal : ProtoConstants.GroupMemberType.GroupMemberType_Manager) + \"\");\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public boolean isMemberInGroup(String memberId, String groupId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n\n        Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);\n        if (members == null || members.size() == 0) {\n            members = loadGroupMemberFromDB(hzInstance, groupId);\n        }\n        for (WFCMessage.GroupMember member : members\n            ) {\n            if (member.getMemberId().equals(memberId) && member.getType() != GroupMemberType_Removed)\n                return true;\n        }\n\n        return false;\n    }\n\n    @Override\n    public ErrorCode canSendMessageInGroup(String memberId, String groupId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n        IMap<String, WFCMessage.GroupInfo> groups = hzInstance.getMap(GROUPS_MAP);\n        WFCMessage.GroupInfo groupInfo = groups.get(groupId);\n        boolean isMute = false;\n        if (groupInfo != null && groupInfo.getDeleted() == 0) {\n            if (groupInfo.getOwner().equals(memberId)) {\n                return ErrorCode.ERROR_CODE_SUCCESS;\n            }\n            isMute = groupInfo.getMute()>0;\n        }\n\n        Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);\n        if (members == null || members.size() == 0) {\n            members = loadGroupMemberFromDB(hzInstance, groupId);\n        }\n\n        boolean isInGroup = false;\n        for (WFCMessage.GroupMember member : members) {\n            if (member.getMemberId().equals(memberId)) {\n                if (member.getType() == GroupMemberType_Silent) {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n\n                if (isMute && member.getType() != GroupMemberType_Manager && member.getType() != GroupMemberType_Owner) {\n                    return ErrorCode.ERROR_CODE_GROUP_MUTED;\n                }\n\n                if (member.getMemberId().equals(memberId) && member.getType() == GroupMemberType_Removed) {\n                    return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n                }\n                isInGroup = true;\n                break;\n            }\n\n        }\n\n        if (!isInGroup) {\n            return ErrorCode.ERROR_CODE_NOT_IN_GROUP;\n        }\n\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public Set<String> getGroupManagers(String groupId, boolean includeOwner) {\n        Set<String> ret = new HashSet<>();\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n\n        Collection<WFCMessage.GroupMember> members = groupMembers.get(groupId);\n        if (members == null || members.size() == 0) {\n            members = loadGroupMemberFromDB(hzInstance, groupId);\n        }\n        for (WFCMessage.GroupMember member : members) {\n            if(member.getType() == GroupMemberType_Manager || (member.getType() == GroupMemberType_Owner && includeOwner)) {\n                ret.add(member.getMemberId());\n            }\n        }\n\n        return ret;\n    }\n\n    @Override\n    public ErrorCode recallMessage(long messageUid, String operatorId, String clientId, boolean isAdmin, ByteBuf ackPayload) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<Long, MessageBundle> mIMap = hzInstance.getMap(MESSAGES_MAP);\n\n        MessageBundle messageBundle = mIMap.get(messageUid);\n        long now = System.currentTimeMillis();\n        if (messageBundle != null) {\n            WFCMessage.Message message = messageBundle.getMessage();\n            boolean canRecall = false;\n            if (isAdmin) {\n                canRecall = true;\n            }\n            boolean isExpired = false;\n            if (!canRecall && message.getFromUser().equals(operatorId)) {\n                if (mRecallTimeLimit >= 0 && now - message.getServerTimestamp() > mRecallTimeLimit * 1000) {\n                    isExpired = true;\n                } else {\n                    canRecall = true;\n                }\n            }\n\n            if (!canRecall && !mDisableGroupManagerRecall && message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_Group) {\n                IMap<String, WFCMessage.GroupInfo> groupMap = hzInstance.getMap(GROUPS_MAP);\n\n                WFCMessage.GroupInfo groupInfo = groupMap.get(message.getConversation().getTarget());\n                if (groupInfo == null) {\n                    LOG.info(\"recall message failure, group {} not exist\", message.getConversation().getTarget());\n                    return ErrorCode.ERROR_CODE_NOT_EXIST;\n                }\n                if (operatorId.equals(groupInfo.getOwner())) {\n                    if(operatorId.equals(message.getFromUser())) {\n                        if(mGroupAllowOwnerRecallSelfMsg) {\n                            canRecall = true;\n                        }\n                    } else {\n                        canRecall = true;\n                    }\n                } else {\n                    if(message.getFromUser().equals(operatorId) && mGroupAllowManagerRecallSelfMsg) {\n                        MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n                        Collection<WFCMessage.GroupMember> members = groupMembers.get(message.getConversation().getTarget());\n                        if (members == null || members.size() == 0) {\n                            members = loadGroupMemberFromDB(hzInstance, message.getConversation().getTarget());\n                        }\n                        for (WFCMessage.GroupMember member : members) {\n                            if (member.getMemberId().equals(operatorId)) {\n                                if (member.getType() == GroupMemberType_Manager || member.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Owner) {\n                                    canRecall = true;\n                                }\n                            }\n                        }\n                    }\n                }\n\n                if(!canRecall && !message.getFromUser().equals(operatorId)) {\n                    boolean isOperatorManager = false;\n                    int senderType = GroupMemberType_Normal;\n                    MultiMap<String, WFCMessage.GroupMember> groupMembers = hzInstance.getMultiMap(GROUP_MEMBERS);\n                    Collection<WFCMessage.GroupMember> members = groupMembers.get(message.getConversation().getTarget());\n                    if (members == null || members.size() == 0) {\n                        members = loadGroupMemberFromDB(hzInstance, message.getConversation().getTarget());\n                    }\n                    for (WFCMessage.GroupMember member : members) {\n                        if (member.getMemberId().equals(operatorId)) {\n                            if (member.getType() == GroupMemberType_Manager || member.getType() == ProtoConstants.GroupMemberType.GroupMemberType_Owner) {\n                                isOperatorManager = true;\n                            }\n                        }\n                        if(member.getMemberId().equals(message.getFromUser())) {\n                            senderType = member.getType();\n                        }\n                    }\n                    if(isOperatorManager && senderType != GroupMemberType_Manager && senderType != GroupMemberType_Owner) {\n                        canRecall = true;\n                    }\n                }\n            }\n\n            if (!canRecall && message.getConversation().getType() == ProtoConstants.ConversationType.ConversationType_ChatRoom) {\n                IMap<String, WFCMessage.ChatroomInfo> chatroomInfoMap = hzInstance.getMap(CHATROOMS);\n                WFCMessage.ChatroomInfo room = chatroomInfoMap.get(message.getConversation().getTarget());\n                //todo check is manager\n            }\n\n            if (!canRecall) {\n                if(isExpired) {\n                    return ErrorCode.ERROR_CODE_RECALL_TIME_EXPIRED;\n                } else {\n                    return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                }\n            }\n            \n            if(message.getContent().getType() == 80) {\n                return ErrorCode.ERROR_CODE_SUCCESS;\n            }\n\n            if(!StringUtil.isNullOrEmpty(mRecallForwardUrl)) {\n                OutputRecallMessageData event = new OutputRecallMessageData(OutputMessageData.fromProtoMessage(message, null), operatorId, System.currentTimeMillis(), isAdmin);\n                m_Server.getCallbackScheduler().execute(() -> {\n                    try {\n                        HttpUtils.httpJsonPost(mRecallForwardUrl, GsonUtil.gson.toJson(event), HttpUtils.HttpPostType.POST_TYPE_Forward_Recall_Callback);\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                        Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n                    }\n                });\n            }\n\n\n            JSONObject json = new JSONObject();\n            json.put(\"s\", message.getFromUser());\n            json.put(\"ts\", message.getServerTimestamp());\n            json.put(\"t\", message.getContent().getType());\n            json.put(\"sc\", message.getContent().getSearchableContent());\n            json.put(\"c\", message.getContent().getContent());\n            json.put(\"e\", message.getContent().getExtra());\n            if (message.getContent().getData() != null && message.getContent().getData().size() > 0) {\n                json.put(\"b\", Base64.getEncoder().encodeToString(message.getContent().getData().toByteArray()));\n            }\n            if (message.getContent().getMediaType() > 0) {\n                json.put(\"mt\", message.getContent().getMediaType());\n            }\n            if (!StringUtil.isNullOrEmpty(message.getContent().getRemoteMediaUrl())) {\n                json.put(\"mu\", message.getContent().getRemoteMediaUrl());\n            }\n\n            String recalledContent = json.toJSONString();\n\n            JSONObject pushData = new JSONObject();\n            pushData.put(\"messageUid\", messageUid);\n\n            message = message.toBuilder().setContent(WFCMessage.MessageContent.newBuilder()\n                .setContent(operatorId)\n                .clearSearchableContent()\n                .clearPushContent()\n                .setPersistFlag(1)\n                .setExpireDuration(0)\n                .setMentionedType(0)\n                .setType(80)\n                .setData(ByteString.copyFrom(String.valueOf(messageUid).getBytes()))\n                .setPushData(pushData.toJSONString())\n                .setExtra(recalledContent)).build();\n            messageBundle.setMessage(message);\n            messageBundle.setFromClientId(clientId);\n\n            databaseStore.deleteMessage(messageUid);\n\n            mIMap.put(messageUid, messageBundle, 7, TimeUnit.DAYS);\n            ackPayload.writeBytes(recalledContent.getBytes(StandardCharsets.UTF_8));\n            return ErrorCode.ERROR_CODE_SUCCESS;\n        } else {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n    }\n\n    public ErrorCode recallCastMessage(long messageUid, String operatorId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<Long, MessageBundle> mIMap = hzInstance.getMap(MESSAGES_MAP);\n\n        MessageBundle messageBundle = mIMap.get(messageUid);\n        if (messageBundle != null) {\n            WFCMessage.Message message = messageBundle.getMessage();\n\n            message = message.toBuilder().setContent(WFCMessage.MessageContent.newBuilder().setContent(operatorId).setType(80).setData(ByteString.copyFrom(String.valueOf(messageUid).getBytes()))).build();\n            messageBundle.setMessage(message);\n            messageBundle.setFromClientId(null);\n\n            databaseStore.deleteMessage(messageUid);\n            mIMap.set(messageUid, messageBundle, 7, TimeUnit.DAYS);\n            return ErrorCode.ERROR_CODE_SUCCESS;\n        } else {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n    }\n\n    @Override\n    public void clearUserMessages(String userId) {\n        mWriteLock.lock();\n        try {\n            userMessages.remove(userId);\n        } finally {\n            mWriteLock.unlock();\n        }\n        if(!keepMessagesWhenDestroyUser) {\n            databaseStore.clearUserMessage(userId);\n        }\n    }\n\n    @Override\n    public WFCMessage.Robot getRobot(String robotId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.Robot> mRobotMap = hzInstance.getMap(ROBOTS);\n        return mRobotMap.get(robotId);\n    }\n\n    @Override\n    public void addRobot(WFCMessage.Robot robot) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.Robot> mUserMap = hzInstance.getMap(ROBOTS);\n        mUserMap.put(robot.getUid(), robot);\n    }\n\n    @Override\n    public void destroyRobot(String robotId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.Robot> mUserMap = hzInstance.getMap(ROBOTS);\n        mUserMap.remove(robotId);\n    }\n\n    @Override\n    public ErrorCode getUserInfo(String fromUser, List<WFCMessage.UserRequest> requestList, WFCMessage.PullUserResult.Builder builder) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.User> mUserMap = hzInstance.getMap(USERS);\n\n        for (WFCMessage.UserRequest request : requestList\n            ) {\n            WFCMessage.User user = mUserMap.get(request.getUid());\n            if (user == null) {\n                user = databaseStore.getPersistUser(request.getUid());\n                if (user != null) {\n                    mUserMap.set(request.getUid(), user);\n                }\n            }\n            WFCMessage.UserResult.Builder resultBuilder = WFCMessage.UserResult.newBuilder();\n            if (user == null) {\n                LOG.warn(\"Get user info, user {} not exist\", request.getUid());\n                user = WFCMessage.User.newBuilder().setUid(request.getUid()).build();\n                resultBuilder.setUser(user);\n                resultBuilder.setCode(ProtoConstants.UserResultCode.NotFound);\n            } else {\n                LOG.debug(\"Get user info, user {}  userDt {} : request {}\",request.getUid(), user.getUpdateDt(), request.getUpdateDt());\n                if (user.getUpdateDt() > request.getUpdateDt()) {\n                    if(!mUserHideProperties.isEmpty() && !user.getUid().equals(fromUser)) {\n                        WFCMessage.User.Builder userBuilder = user.toBuilder();\n                        for (Integer i:mUserHideProperties) {\n                            if(i == Modify_Gender) {\n                                userBuilder.clearGender();\n                            } else if(i == Modify_Mobile) {\n                                userBuilder.clearMobile();\n                            } else if(i == Modify_Email) {\n                                userBuilder.clearEmail();\n                            } else if(i == Modify_Address) {\n                                userBuilder.clearAddress();\n                            } else if(i == Modify_Company) {\n                                userBuilder.clearCompany();\n                            } else if(i == Modify_Social) {\n                                userBuilder.clearSocial();\n                            } else if(i == Modify_Extra) {\n                                userBuilder.clearExtra();\n                            }\n                        }\n                        user = userBuilder.build();\n                    }\n                    resultBuilder.setUser(user);\n                    resultBuilder.setCode(ProtoConstants.UserResultCode.Success);\n                } else {\n                    user = WFCMessage.User.newBuilder().setUid(request.getUid()).build();\n                    resultBuilder.setUser(user);\n                    resultBuilder.setCode(ProtoConstants.UserResultCode.NotModified);\n                }\n            }\n            builder.addResult(resultBuilder.build());\n\n        }\n\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode modifyUserInfo(String userId, WFCMessage.ModifyMyInfoRequest request) throws Exception {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.User> mUserMap = hzInstance.getMap(USERS);\n\n        WFCMessage.User user = mUserMap.get(userId);\n        if (user == null) {\n            user = databaseStore.getPersistUser(userId);\n            if (user != null) {\n                mUserMap.set(userId, user);\n            } else {\n                return ErrorCode.ERROR_CODE_NOT_EXIST;\n            }\n        }\n\n        WFCMessage.User.Builder builder = user.toBuilder();\n        boolean modified = false;\n        for (WFCMessage.InfoEntry entry : request.getEntryList()\n            ) {\n            switch (entry.getType()) {\n                case Modify_DisplayName:\n                    if(!StringUtil.isNullOrEmpty(entry.getValue())) {\n                        if (!mSensitiveOnlyMessage) {\n                            Set<String> matched = handleSensitiveWord(entry.getValue());\n                            if (matched != null && !matched.isEmpty()) {\n                                return ErrorCode.ERROR_CODE_SENSITIVE_MATCHED;\n                            }\n                        }\n\n                        if(!isAllowName(entry.getValue())) {\n                            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n                        }\n                    }\n\n                    builder.setDisplayName(entry.getValue());\n                    modified = true;\n                    break;\n                case Modify_Gender:\n                    builder.setGender(Integer.parseInt(entry.getValue()));\n                    modified = true;\n                    break;\n                case Modify_Portrait:\n                    builder.setPortrait(entry.getValue());\n                    modified = true;\n                    break;\n                //禁止客户端直接修改电话号码，只能通过admin api来修改\n//                case Modify_Mobile:\n//                    builder.setMobile(entry.getValue());\n//                    modified = true;\n//                    break;\n                case Modify_Email:\n                    builder.setEmail(entry.getValue());\n                    modified = true;\n                    break;\n                case Modify_Address:\n                    builder.setAddress(entry.getValue());\n                    modified = true;\n                    break;\n                case Modify_Company:\n                    builder.setCompany(entry.getValue());\n                    modified = true;\n                    break;\n                case Modify_Social:\n                    builder.setSocial(entry.getValue());\n                    modified = true;\n                    break;\n                case Modify_Extra:\n                    builder.setExtra(entry.getValue());\n                    modified = true;\n                    break;\n                default:\n                    break;\n            }\n        }\n\n        if (modified) {\n            builder.setUpdateDt(System.currentTimeMillis());\n            user = builder.build();\n            databaseStore.updateUser(user);\n            mUserMap.set(userId, user);\n\n            IMHandler.getPublisher().publishNotification(IMTopic.NotifyUserInfoTopic, user.getUid(), 0, null);\n            callbackUserInfoEvent(user);\n\n            return ErrorCode.ERROR_CODE_SUCCESS;\n        } else {\n            return ErrorCode.ERROR_CODE_NOT_MODIFIED;\n        }\n\n    }\n\n    public void forceCleanOnlineStatus(String userId, String clientId) {\n        if (m_Server.isShutdowning()) {\n            return;\n        }\n\n        if(!mMultiPlatformNotification || m_Server.getStore().sessionsStore().isMultiEndpointSupported()) {\n            WFCMessage.UserSettingEntry pcentry = getUserSetting(userId, kUserSettingPCOnline, \"PC\");\n            if (pcentry != null && !StringUtil.isNullOrEmpty(pcentry.getValue()) && pcentry.getValue().contains(clientId)) {\n                updateUserSettings(userId, WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingPCOnline).setKey(\"PC\").setValue(\"\").build(), clientId);\n            }\n\n            WFCMessage.UserSettingEntry padentry = getUserSetting(userId, kUserSettingPCOnline, \"Pad\");\n            if (padentry != null && !StringUtil.isNullOrEmpty(padentry.getValue()) && padentry.getValue().contains(clientId)) {\n                updateUserSettings(userId, WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingPCOnline).setKey(\"Pad\").setValue(\"\").build(), clientId);\n            }\n        }\n    }\n\n    private boolean isOnlineValueEqual(WFCMessage.UserSettingEntry pcentry, String newValue) {\n        if(pcentry == null) {\n            return StringUtil.isNullOrEmpty(newValue);\n        }\n\n        String oldValue = pcentry.getValue();\n        if(StringUtil.isNullOrEmpty(oldValue) && StringUtil.isNullOrEmpty(newValue)) {\n            return true;\n        }\n\n        if(StringUtil.isNullOrEmpty(oldValue) || StringUtil.isNullOrEmpty(newValue)) {\n            return false;\n        }\n\n        String[] ssOld = oldValue.split(\"\\\\|\");\n        String[] ssNew = newValue.split(\"\\\\|\");\n        if(ssOld.length != 4 || ssNew.length != 4 || !ssOld[1].equals(ssNew[1]) || !ssOld[2].equals(ssNew[2]) || !ssOld[3].equals(ssNew[3])) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public void updateUserOnlineSetting(MemorySessionStore.Session session, boolean online) {\n        if(!mMultiPlatformNotification) {\n            return;\n        }\n        if (m_Server.getStore().sessionsStore().isMultiEndpointSupported()) {\n            return;\n        }\n\n        if (m_Server.isShutdowning()) {\n            return;\n        }\n\n        String pcValue = null;\n        String padValue = null;\n        String wearableValue = null;\n        String tvValue = null;\n        for (MemorySessionStore.Session s : m_Server.getStore().sessionsStore().sessionForUser(session.username)) {\n            if (s.getDeleted() != 0 || !m_Server.getConnectionsManager().isConnected(s.getClientID())) {\n                continue;\n            }\n\n            switch (s.getPlatform()) {\n                case Platform_LINUX:\n                case Platform_Windows:\n                case Platform_OSX:\n                case Platform_HarmonyPC:\n                    pcValue = System.currentTimeMillis() + \"|\" + s.getPlatform() + \"|\" + s.getClientID() + \"|\" + s.getPhoneName();\n                    break;\n                case Platform_iPad:\n                case Platform_APad:\n                case Platform_HarmonyPad:\n                    padValue = System.currentTimeMillis() + \"|\" + s.getPlatform() + \"|\" + s.getClientID() + \"|\" + s.getPhoneName();\n                    break;\n                case Platform_AndroidWearable:\n                case Platform_HarmonyWearable:\n                    wearableValue = System.currentTimeMillis() + \"|\" + s.getPlatform() + \"|\" + s.getClientID() + \"|\" + s.getPhoneName();\n                    break;\n                case Platform_AndroidTV:\n                case Platform_AppleTV:\n                case Platform_HarmonyTV:\n                    tvValue = System.currentTimeMillis() + \"|\" + s.getPlatform() + \"|\" + s.getClientID() + \"|\" + s.getPhoneName();\n                    break;\n                default:\n                    break;\n            }\n        }\n\n        WFCMessage.UserSettingEntry pcentry = getUserSetting(session.getUsername(), kUserSettingPCOnline, \"PC\");\n        if (!isOnlineValueEqual(pcentry, pcValue)) {\n            updateUserSettings(session.username, WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingPCOnline).setKey(\"PC\").setValue(pcValue==null?\"\":pcValue).build(), session.clientID);\n        }\n\n        WFCMessage.UserSettingEntry padentry = getUserSetting(session.getUsername(), kUserSettingPCOnline, \"Pad\");\n        if (!isOnlineValueEqual(padentry, padValue)) {\n            updateUserSettings(session.username, WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingPCOnline).setKey(\"Pad\").setValue(padValue==null?\"\":padValue).build(), session.clientID);\n        }\n\n        WFCMessage.UserSettingEntry wearableEntry = getUserSetting(session.getUsername(), kUserSettingPCOnline, \"Wearable\");\n        if (!isOnlineValueEqual(wearableEntry, wearableValue)) {\n            updateUserSettings(session.username, WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingPCOnline).setKey(\"Wearable\").setValue(wearableValue==null?\"\":wearableValue).build(), session.clientID);\n        }\n\n        WFCMessage.UserSettingEntry tvEntry = getUserSetting(session.getUsername(), kUserSettingPCOnline, \"TV\");\n        if (!isOnlineValueEqual(tvEntry, tvValue)) {\n            updateUserSettings(session.username, WFCMessage.ModifyUserSettingReq.newBuilder().setScope(kUserSettingPCOnline).setKey(\"TV\").setValue(tvValue==null?\"\":tvValue).build(), session.clientID);\n        }\n    }\n\n    @Override\n    public ErrorCode modifyUserStatus(String userId, int status) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, Integer> mUserMap = hzInstance.getMap(USER_STATUS);\n        if (status == 0) {\n            mUserMap.delete(userId);\n        } else {\n            mUserMap.put(userId, status);\n        }\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public int getUserStatus(String userId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, Integer> mUserMap = hzInstance.getMap(USER_STATUS);\n        Integer status = mUserMap.get(userId);\n\n        if (status != null) {\n            return status;\n        }\n\n        return 0;\n    }\n\n    @Override\n    public List<InputOutputUserBlockStatus> getUserStatusList() {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, Integer> mUserMap = hzInstance.getMap(USER_STATUS);\n        ArrayList<InputOutputUserBlockStatus> out = new ArrayList<>();\n        for (Map.Entry<String, Integer> entry : mUserMap.entrySet()) {\n            if(entry.getValue() > 0) {\n                out.add(new InputOutputUserBlockStatus(entry.getKey(), entry.getValue()));\n            }\n        }\n        return out;\n    }\n\n    @Override\n    public ErrorCode updateUserInfo(InputOutputUserInfo userInfo, int flag) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.User> mUserMap = hzInstance.getMap(USERS);\n        WFCMessage.User user = mUserMap.get(userInfo.getUserId());\n        if(user == null) {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n        WFCMessage.User.Builder builder = user.toBuilder();\n        if((flag & Update_User_DisplayName) > 0) {\n            builder.setDisplayName(userInfo.getDisplayName() == null ? \"\" : userInfo.getDisplayName());\n        }\n        if((flag & Update_User_Portrait) > 0) {\n            builder.setPortrait(userInfo.getPortrait() == null ? \"\" : userInfo.getPortrait());\n        }\n        if((flag & Update_User_Gender) > 0) {\n            builder.setGender(userInfo.getGender());\n        }\n        if((flag & Update_User_Mobile) > 0) {\n            builder.setMobile(userInfo.getMobile() == null ? \"\" : userInfo.getMobile());\n        }\n        if((flag & Update_User_Email) > 0) {\n            builder.setEmail(userInfo.getEmail() == null ? \"\" : userInfo.getEmail());\n        }\n        if((flag & Update_User_Address) > 0) {\n            builder.setAddress(userInfo.getAddress() == null ? \"\" : userInfo.getAddress());\n        }\n        if((flag & Update_User_Company) > 0) {\n            builder.setCompany(userInfo.getCompany() == null ? \"\" : userInfo.getCompany());\n        }\n        if((flag & Update_User_Social) > 0) {\n            builder.setSocial(userInfo.getSocial() == null ? \"\" : userInfo.getSocial());\n        }\n        if((flag & Update_User_Extra) > 0) {\n            builder.setExtra(userInfo.getExtra() == null ? \"\" : userInfo.getExtra());\n        }\n        if((flag & Update_User_Name) > 0) {\n            if(StringUtil.isNullOrEmpty(userInfo.getName())) {\n                LOG.error(\"Modify user info failure, name not exist!\");\n                return ErrorCode.INVALID_PARAMETER;\n            }\n            builder.setName(userInfo.getName());\n        }\n        builder.setUpdateDt(System.currentTimeMillis());\n        user = builder.build();\n        try {\n            databaseStore.updateUser(user);\n        } catch (Exception e) {\n            e.printStackTrace();\n            return ErrorCode.ERROR_CODE_SERVER_ERROR;\n        }\n\n        IMHandler.getPublisher().publishNotification(IMTopic.NotifyUserInfoTopic, user.getUid(), 0, null);\n\n        mUserMap.put(user.getUid(), user);\n        callbackUserInfoEvent(user);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public void addUserInfo(WFCMessage.User user) throws Exception {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.User> mUserMap = hzInstance.getMap(USERS);\n        if (databaseStore.isUidAndNameConflict(user.getUid(), user.getName())) {\n            throw new Exception(\"用户名不能重复，必须唯一！！！\");\n        }\n        databaseStore.updateUser(user);\n        mUserMap.put(user.getUid(), user);\n\n        callbackUserInfoEvent(user);\n    }\n\n    @Override\n    public void destroyUser(String userId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.User> mUserMap = hzInstance.getMap(USERS);\n        WFCMessage.User us = mUserMap.get(userId);\n        if (us != null) {\n            WFCMessage.User.Builder builder = us.toBuilder().setUpdateDt(System.currentTimeMillis()).setDeleted(1);\n\n            if(keepFullInfoWhenDestroyUser) {\n                if(!keepMobileWhenDestroyUser) {\n                    builder.clearMobile();\n                }\n            } else {\n                builder.setUid(userId)\n                    .setName(userId)\n                    .clearAddress()\n                    .clearCompany()\n                    .clearEmail()\n                    .clearExtra()\n                    .clearMobile()\n                    .clearPortrait()\n                    .clearGender()\n                    .clearSocial();\n                if (!keepDisplayNameWhenDestroyUser) {\n                    builder.clearDisplayName();\n                }\n            }\n\n            us = builder.build();\n            try {\n                databaseStore.updateUser(us);\n            } catch (Exception e) {\n                e.printStackTrace();\n                Utility.printExecption(LOG, e);\n            }\n            mUserMap.put(userId, us);\n        }\n    }\n\n    @Override\n    public void updateUserInfo(WFCMessage.User user) throws Exception {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.User> mUserMap = hzInstance.getMap(USERS);\n        if(mUserMap.get(user.getUid()) != null) {\n            databaseStore.updateUser(user);\n            mUserMap.put(user.getUid(), user);\n        }\n    }\n\n    @Override\n    public WFCMessage.User getUserInfo(String userId) {\n        if (StringUtil.isNullOrEmpty(userId)) {\n            return null;\n        }\n\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.User> mUserMap = hzInstance.getMap(USERS);\n        WFCMessage.User user = mUserMap.get(userId);\n        return user;\n    }\n\n    @Override\n    public WFCMessage.User getUserInfoByName(String name) {\n        String userId = databaseStore.getUserIdByName(name);\n        return getUserInfo(userId);\n    }\n\n    @Override\n    public WFCMessage.User getUserInfoByMobile(String mobile) {\n        String userId = databaseStore.getUserIdByMobile(mobile);\n        return getUserInfo(userId);\n    }\n\n    @Override\n    public List<WFCMessage.User> getUserInfosByEmail(String email) {\n        return databaseStore.getUserInfosByEmail(email);\n    }\n\n    @Override\n    public List<WFCMessage.User> getUserInfoList(int count, int offset) {\n        return databaseStore.getAllUsers(count, offset);\n    }\n\n    @Override\n    public List<String> getUserRobotIds(String userId) {\n        return databaseStore.getUserRobotIds(userId);\n    }\n\n    // 电话号码校验正则表达式（支持中国大陆手机号和固话）\n    private static final String PHONE_REGEX = \"^\\\\s*\" +  // 允许开头空白\n        \"(?:\" +\n        \"(1[0-9])\\\\d{9}\" +\n        \"|\" +\n        \"((0\\\\d{2,3})|(\\\\(0\\\\d{2,3}\\\\)))\" +\n        \"[-\\\\s.]?\" +\n        \"\\\\d{7,8}\" +\n        \"|\" +\n        \"\\\\d{7,8}\" +\n        \")\\\\s*$\";\n\n    private static final Pattern PHONE_PATTERN = Pattern.compile(PHONE_REGEX);\n    private static final Pattern PHONE_PART_PATTERN = Pattern.compile(\"^1\\\\d{0,10}$\");\n\n    public static boolean isPhoneNumber(String phone) {\n        if (phone == null || phone.trim().isEmpty()) {\n            return false;\n        }\n        Matcher matcher = PHONE_PATTERN.matcher(phone);\n        return matcher.matches();\n    }\n\n    public static boolean isPhoneNumberPart(String str) {\n        if (str == null || str.trim().isEmpty()) {\n            return false;\n        }\n\n        Matcher matcher = PHONE_PART_PATTERN.matcher(str);\n        return matcher.matches();\n    }\n\n    @Override\n    public ErrorCode searchUser(String userId, String keyword, int searchType, int userType, int page, List<WFCMessage.User> users) {\n        if (mDisableSearch) {\n            return ErrorCode.ERROR_CODE_NOT_IMPLEMENT;\n        }\n\n        if (mDisableNicknameSearch && searchType == ProtoConstants.SearchUserType.SearchUserType_General) {\n            searchType = ProtoConstants.SearchUserType.SearchUserType_Name_Mobile_UserId;\n        }\n\n        if(mDisableUserIdSearch && searchType == ProtoConstants.SearchUserType.SearchUserType_Name_Mobile_UserId) {\n            searchType = ProtoConstants.SearchUserType.SearchUserType_Name_Mobile;\n        }\n\n        if(mDisableUserIdSearch && searchType == ProtoConstants.SearchUserType.SearchUserType_General) {\n            searchType = ProtoConstants.SearchUserType.SearchUserType_Name_Mobile_DisplayName;\n        }\n\n        if(mDisableUserIdSearch && searchType == ProtoConstants.SearchUserType.SearchUserType_UserId) {\n            return ErrorCode.ERROR_CODE_NOT_IMPLEMENT;\n        }\n\n        if(mFriendSearchRateLimiter != null && !isPhoneNumberPart(keyword)) {\n            //非电话号码，允许多少次搜索。\n            if(!mFriendSearchRateLimiter.isGranted(userId)) {\n                LOG.error(\"User {} search user mobile over frequency, keyword {}, searchType {}\", userId, keyword, searchType);\n                return ErrorCode.ERROR_CODE_OVER_FREQUENCY;\n            }\n        }\n\n        List<WFCMessage.User> matchedUsers = databaseStore.searchUserFromDB(keyword, searchType, userType, page);\n        if(mFriendSearchEmpthMobileRateLimiter != null && matchedUsers.isEmpty() && isPhoneNumber(keyword)) {\n            //查电话号码为空\n            if(!mFriendSearchEmpthMobileRateLimiter.isGranted(userId)) {\n                LOG.error(\"User {} search user over frequency, keyword {}, searchType {}\", userId, keyword, searchType);\n                return ErrorCode.ERROR_CODE_OVER_FREQUENCY;\n            }\n        }\n\n        users.addAll(matchedUsers);\n\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public boolean updateSystemSetting(int id, String value, String desc) {\n        return databaseStore.updateSystemSetting(id, value, desc);\n    }\n\n    @Override\n    public SystemSettingPojo getSystemSetting(int id) {\n        return databaseStore.getSystemSetting(id);\n    }\n\n    @Override\n    public void createChatroom(String chatroomId, WFCMessage.ChatroomInfo chatroomInfo) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.ChatroomInfo> chatroomInfoMap = hzInstance.getMap(CHATROOMS);\n        WFCMessage.ChatroomInfo preInfo = chatroomInfoMap.get(chatroomId);\n        if (preInfo != null) {\n            WFCMessage.ChatroomInfo.Builder builder = preInfo.toBuilder();\n            if (!StringUtil.isNullOrEmpty(chatroomInfo.getTitle())) {\n                builder.setTitle(chatroomInfo.getTitle());\n            }\n\n            if (!StringUtil.isNullOrEmpty(chatroomInfo.getDesc())) {\n                builder.setDesc(chatroomInfo.getDesc());\n            }\n\n            if (!StringUtil.isNullOrEmpty(chatroomInfo.getPortrait())) {\n                builder.setPortrait(chatroomInfo.getPortrait());\n            }\n\n            if (!StringUtil.isNullOrEmpty(chatroomInfo.getExtra())) {\n                builder.setExtra(chatroomInfo.getExtra());\n            }\n\n            builder.setState(chatroomInfo.getState());\n\n            chatroomInfo = builder.build();\n        }\n        chatroomInfoMap.put(chatroomId, chatroomInfo);\n        callbackChatroomInfoUpdateEvent(chatroomId, Chatroom_Event_Create);\n    }\n\n    @Override\n    public void destoryChatroom(String chatroomId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.ChatroomInfo> chatroomInfoMap = hzInstance.getMap(CHATROOMS);\n        WFCMessage.ChatroomInfo room = chatroomInfoMap.get(chatroomId);\n        if (room != null) {\n            clearChatroomMembers(chatroomId);\n            room = room.toBuilder().setUpdateDt(System.currentTimeMillis()).setState(ProtoConstants.ChatroomState.Chatroom_State_End).build();\n            chatroomInfoMap.put(chatroomId, room);\n            callbackChatroomInfoUpdateEvent(chatroomId, Chatroom_Event_Destroy);\n        }\n    }\n\n    @Override\n    public WFCMessage.ChatroomInfo getChatroomInfo(String chatroomId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.ChatroomInfo> chatroomInfoMap = hzInstance.getMap(CHATROOMS);\n        return chatroomInfoMap.get(chatroomId);\n    }\n\n    @Override\n    public WFCMessage.ChatroomMemberInfo getChatroomMemberInfo(String chatroomId, final int maxMemberCount) {\n        MultiMap<String, UserClientEntry> chatroomMembers = m_Server.getHazelcastInstance().getMultiMap(CHATROOM_MEMBER_IDS);\n        Collection<UserClientEntry> members = chatroomMembers.get(chatroomId);\n\n        if (members != null) {\n            ArrayList<String> memberIds = new ArrayList<>();\n            if (members.size() <= maxMemberCount) {\n                    members.stream().forEach(new Consumer<UserClientEntry>() {\n                        @Override\n                        public void accept(UserClientEntry userClientEntry) {\n                            memberIds.add(userClientEntry.userId);\n                        }\n                    });\n            } else {\n                Spliterator<UserClientEntry> p = members.spliterator();\n                while (p.estimateSize() > 2*maxMemberCount) {\n                    p = p.trySplit();\n                }\n\n                p.forEachRemaining(new Consumer<UserClientEntry>() {\n                    public void accept(UserClientEntry s) {\n                        if (memberIds.size() < maxMemberCount) {\n                            memberIds.add(s.userId);\n                        }\n                    }\n                });\n            }\n            return WFCMessage.ChatroomMemberInfo.newBuilder().setMemberCount(members.size()).addAllMembers(memberIds).build();\n        }\n\n        return WFCMessage.ChatroomMemberInfo.newBuilder().setMemberCount(0).build();\n\n    }\n    @Override\n    public int getChatroomMemberCount(String chatroomId) {\n        return m_Server.getHazelcastInstance().getMultiMap(CHATROOM_MEMBER_IDS).valueCount(chatroomId);\n    }\n\n    @Override\n    public ErrorCode verifyToken(String userId, String token, List<String> serverIPs, List<Integer> ports) {\n        String tokenUserId = Tokenor.getUserId(token.getBytes());\n\n        if (tokenUserId != null) {\n            if (tokenUserId.equals(userId)) {\n                String serverIp = m_Server.getServerIp();\n                String longPort = m_Server.getLongPort();\n                String shortPort = m_Server.getShortPort();\n                if (!StringUtil.isNullOrEmpty(serverIp)) {\n                    serverIPs.add(serverIp);\n                }\n                ports.add(Integer.parseInt(longPort));\n                ports.add(Integer.parseInt(shortPort));\n            } else {\n                return ErrorCode.ERROR_CODE_TOKEN_ERROR;\n            }\n        } else {\n            return ErrorCode.ERROR_CODE_TOKEN_ERROR;\n        }\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode isAllowUserMessage(String targetUser, String fromUser, int line) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n\n        Collection<FriendData> friendDatas = friendsMap.get(targetUser);\n\n        if (friendDatas == null || friendDatas.size() == 0) {\n            friendDatas = loadFriend(friendsMap, targetUser);\n        }\n\n        for (FriendData friendData : friendDatas) {\n            if (friendData.getFriendUid().equals(fromUser)) {\n                if (friendData.getBlacked() == 1) {\n                    return ErrorCode.ERROR_CODE_IN_BLACK_LIST;\n                } else {\n                    if (friendData.getState() == 0) {\n                        return ErrorCode.ERROR_CODE_SUCCESS;\n                    } else {\n                        break;\n                    }\n                }\n            }\n        }\n\n\n        if (mDisableStrangerChat) {\n            //在禁止私聊时，是否是允许私聊的用户id\n            if(mAllowStrangerChatSet.contains(targetUser) || mAllowStrangerChatSet.contains(fromUser) || mAllowStrangerLineSet.contains(line)) {\n                return ErrorCode.ERROR_CODE_SUCCESS;\n            }\n\n            //在禁止私聊时，允许机器人，物联网设备及管理员进行私聊。\n            IMap<String, WFCMessage.User> mUserMap = hzInstance.getMap(USERS);\n            WFCMessage.User target = mUserMap.get(targetUser);\n            if (target != null && target.getType() != ProtoConstants.UserType.UserType_Normal) {\n                return ErrorCode.ERROR_CODE_SUCCESS;\n            }\n            target = mUserMap.get(fromUser);\n            if (target != null && target.getType() != ProtoConstants.UserType.UserType_Normal) {\n                return ErrorCode.ERROR_CODE_SUCCESS;\n            }\n            //admin的usertype为3，所以不需要hardcode为admin添加例外\n//            if (targetUser.equals(\"admin\") || fromUser.equals(\"admin\")) {\n//                return ErrorCode.ERROR_CODE_SUCCESS;\n//            }\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode isBlacked(String fromUser, String userId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n\n        Collection<FriendData> friendDatas = friendsMap.get(fromUser);\n\n        if (friendDatas == null || friendDatas.size() == 0) {\n            friendDatas = loadFriend(friendsMap, fromUser);\n        }\n\n        for (FriendData friendData : friendDatas) {\n            if (friendData.getFriendUid().equals(userId)) {\n                if (friendData.getBlacked() == 1) {\n                    return ErrorCode.ERROR_CODE_IN_BLACK_LIST;\n                } else {\n                    break;\n                }\n            }\n        }\n\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    synchronized Collection<FriendData> loadFriend(MultiMap<String, FriendData> friendsMap, String userId) {\n        Collection<FriendData> friends = databaseStore.getPersistFriends(userId);\n        if (friends != null) {\n            for (FriendData friend : friends) {\n                friendsMap.put(userId, friend);\n            }\n        } else {\n            friends = new ArrayList<>();\n        }\n        return friends;\n    }\n\n    synchronized Collection<WFCMessage.FriendRequest> loadFriendRequest(MultiMap<String, WFCMessage.FriendRequest> requestMap, String userId) {\n        Collection<WFCMessage.FriendRequest> requests = databaseStore.getPersistFriendRequests(userId);\n        if (requests != null) {\n            for (WFCMessage.FriendRequest r : requests\n                ) {\n                requestMap.put(userId, r);\n            }\n        } else {\n            requests = new ArrayList<>();\n        }\n        return requests;\n    }\n\n    @Override\n    public List<FriendData> getFriendList(String userId, String clientId, long version) {\n        List<FriendData> out = new ArrayList<FriendData>();\n\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n        Collection<FriendData> friends = friendsMap.get(userId);\n        if (friends == null || friends.size() == 0) {\n            friends = loadFriend(friendsMap, userId);\n        }\n\n        boolean needFriendMigrate = false;\n\n        if (!StringUtil.isNullOrEmpty(clientId)) {\n            MemorySessionStore.Session session = m_Server.getStore().sessionsStore().getSession(clientId);\n            if(session != null && session.getMqttVersion() != null && session.getMqttVersion().protocolLevel() < MqttVersion.Wildfire_2.protocolLevel()) {\n                needFriendMigrate = true;\n            }\n        }\n\n        for (FriendData friend : friends) {\n            if (friend.getTimestamp() > version) {\n                if (needFriendMigrate) {\n                    if (friend.getBlacked() > 0) {\n                        friend.setState(2);\n                    }\n                    out.add(friend);\n                } else {\n                    out.add(friend);\n                }\n\n            }\n        }\n\n        if(mSyncDataPartSize > 0 && out.size() > mSyncDataPartSize) {\n            out.sort(Comparator.comparingLong(FriendData::getTimestamp));\n            out = out.subList(0, mSyncDataPartSize);\n        }\n\n        return out;\n    }\n\n    @Override\n    public void clearUserFriend(String userId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n\n        Collection<FriendData> friendDatas = friendsMap.get(userId);\n        if (friendDatas == null || friendDatas.size() == 0) {\n            friendDatas = loadFriend(friendsMap, userId);\n        }\n\n        databaseStore.removeUserFriend(userId);\n        databaseStore.removeUserFriendRequest(userId);\n\n        MultiMap<String, WFCMessage.FriendRequest> requestMap = hzInstance.getMultiMap(USER_FRIENDS_REQUEST);\n        requestMap.remove(userId);\n\n\n        if (friendDatas != null) {\n            for (FriendData fd : friendDatas) {\n                friendsMap.remove(fd.getFriendUid());\n            }\n            friendsMap.remove(userId);\n        }\n    }\n\n    @Override\n    public List<WFCMessage.FriendRequest> getFriendRequestList(String userId, long version) {\n        List<WFCMessage.FriendRequest> out = new ArrayList<>();\n\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, WFCMessage.FriendRequest> requestMap = hzInstance.getMultiMap(USER_FRIENDS_REQUEST);\n        Collection<WFCMessage.FriendRequest> requests = requestMap.get(userId);\n        if (requests == null || requests.size() == 0) {\n            requests = loadFriendRequest(requestMap, userId);\n        }\n\n        for (WFCMessage.FriendRequest request : requests) {\n            if (request.getUpdateDt() > version) {\n                out.add(request);\n            }\n        }\n\n        if(mSyncDataPartSize > 0 && out.size() > mSyncDataPartSize) {\n            out.sort(Comparator.comparingLong(WFCMessage.FriendRequest::getUpdateDt));\n            out = out.subList(0, mSyncDataPartSize);\n        }\n        return out;\n    }\n\n    @Override\n    public ErrorCode saveAddFriendRequest(String userId, WFCMessage.AddFriendRequest request, long[] head, boolean isAdmin, boolean isRobot) {\n        if (!isAdmin && mDisableFriendRequest) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        if(!isRobot && !isAdmin && mFriendRateLimiter != null) {\n            if(!mFriendRateLimiter.isGranted(userId)) {\n                LOG.error(\"User {} request add friend over frequency\", userId);\n                return ErrorCode.ERROR_CODE_OVER_FREQUENCY;\n            }\n        }\n\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, WFCMessage.FriendRequest> requestMap = hzInstance.getMultiMap(USER_FRIENDS_REQUEST);\n\n        WFCMessage.UserSettingEntry userSettingData = getUserSetting(request.getTargetUid(), kUserSettingAddFriendStrategy, \"\");\n        boolean noVerify = userSettingData != null && \"1\".equals(userSettingData.getValue());\n        boolean noAllow = userSettingData != null && \"2\".equals(userSettingData.getValue());\n\n        if(noAllow) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n        Collection<WFCMessage.FriendRequest> requests = requestMap.get(userId);\n        if (requests == null || requests.size() == 0) {\n            requests = loadFriendRequest(requestMap, userId);\n        }\n\n        WFCMessage.FriendRequest existRequest = null;\n\n        for (WFCMessage.FriendRequest tmpRequest : requests) {\n            if (tmpRequest.getToUid().equals(request.getTargetUid())) {\n                existRequest = tmpRequest;\n                break;\n            }\n        }\n\n        if (!noVerify && existRequest != null && existRequest.getStatus() != ProtoConstants.FriendRequestStatus.RequestStatus_Accepted && !isAdmin) {\n            if (existRequest.getStatus() == ProtoConstants.FriendRequestStatus.RequestStatus_Rejected\n                && System.currentTimeMillis() - existRequest.getUpdateDt() < mFriendRejectDuration) {\n                return ErrorCode.ERROR_CODE_FRIEND_REQUEST_BLOCKED;\n            }\n\n            if (!(mFriendRequestDuration > 0 && System.currentTimeMillis() - existRequest.getUpdateDt() > mFriendRequestDuration)) {\n                if(System.currentTimeMillis() - existRequest.getUpdateDt() > 5 * 60 * 1000) {\n                    return ErrorCode.ERROR_CODE_FRIEND_ALREADY_REQUEST;\n                } else {\n                    mWriteLock.lock();\n                    try {\n                        String repeatKey = userId + \"-\" + existRequest.getToUid();\n                        Long lastTime = repeatFriendRequest.get(repeatKey);\n                        if(lastTime != null && System.currentTimeMillis() - lastTime < 5 * 60 * 1000) {\n                            return ErrorCode.ERROR_CODE_FRIEND_ALREADY_REQUEST;\n                        }\n                        repeatFriendRequest.put(repeatKey, System.currentTimeMillis());\n                    } finally {\n                        mWriteLock.unlock();\n                    }\n                }\n            }\n        }\n\n        FriendData friendData1 = getFriendData(userId, request.getTargetUid());\n        if (friendData1 != null && friendData1.getState() == 0) {\n            return ErrorCode.ERROR_CODE_ALREADY_FRIENDS;\n        }\n\n        FriendData friendData2 = getFriendData(request.getTargetUid(), userId);\n        if (friendData2 != null && friendData2.getBlacked() > 0 && !isAdmin) {\n            return ErrorCode.ERROR_CODE_IN_BLACK_LIST;\n        }\n\n        WFCMessage.FriendRequest newRequest = WFCMessage.FriendRequest\n            .newBuilder()\n            .setFromUid(userId)\n            .setToUid(request.getTargetUid())\n            .setReason(request.getReason())\n            .setExtra(request.getExtra())\n            .setStatus(ProtoConstants.FriendRequestStatus.RequestStatus_Sent)\n            .setToReadStatus(noVerify)\n            .setUpdateDt(System.currentTimeMillis())\n            .build();\n\n        databaseStore.persistOrUpdateFriendRequest(newRequest);\n        requestMap.remove(userId);\n        requestMap.remove(request.getTargetUid());\n\n\n        if(noVerify) {\n            WFCMessage.HandleFriendRequest handleFriendRequest = WFCMessage.HandleFriendRequest.newBuilder().setTargetUid(userId).setStatus(ProtoConstants.FriendRequestStatus.RequestStatus_Accepted).build();\n            ServerAPIHelper.sendRequest(request.getTargetUid(), null, IMTopic.HandleFriendRequestTopic, handleFriendRequest.toByteArray(), null, ProtoConstants.RequestSourceType.Request_From_User);\n        }\n\n        head[0] = newRequest.getUpdateDt();\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode SyncFriendRequestUnread(String userId, long unreadDt, long[] head) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, WFCMessage.FriendRequest> requestMap = hzInstance.getMultiMap(USER_FRIENDS_REQUEST);\n\n        long curTS = System.currentTimeMillis();\n        head[0] = curTS;\n\n        databaseStore.persistFriendRequestUnreadStatus(userId, unreadDt, curTS);\n        requestMap.remove(userId);\n\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode handleFriendRequest(String userId, WFCMessage.HandleFriendRequest request, WFCMessage.Message.Builder msgBuilder, long[] heads, boolean isAdmin) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n\n        boolean alreadyFriend = false;\n        if(!isAdmin && request.getStatus() == ProtoConstants.FriendRequestStatus.RequestStatus_Accepted) {\n            MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n\n            Collection<FriendData> friends = friendsMap.get(userId);\n            if (friends == null || friends.size() == 0) {\n                friends = loadFriend(friendsMap, userId);\n            }\n\n            for (FriendData fd : friends) {\n                if (fd.getFriendUid().equals(request.getTargetUid())) {\n                    if (fd.getState() == 0) {\n                        alreadyFriend = true;\n                    }\n                    break;\n                }\n            }\n        }\n\n        if (isAdmin) {\n            MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n\n            FriendData friendData1 = null;\n            Collection<FriendData> friendDatas = friendsMap.get(userId);\n            if (friendDatas == null || friendDatas.size() == 0) {\n                friendDatas = loadFriend(friendsMap, userId);\n            }\n            for (FriendData fd : friendDatas) {\n                if (fd.getFriendUid().equals(request.getTargetUid())) {\n                    friendData1 = fd;\n                    break;\n                }\n            }\n            if (friendData1 == null) {\n                friendData1 = new FriendData(userId, request.getTargetUid(), \"\", request.getExtra(), request.getStatus(), 0, System.currentTimeMillis());\n            } else {\n                friendData1.setState(request.getStatus());\n                friendData1.setExtra(request.getExtra());\n                friendData1.setTimestamp(System.currentTimeMillis());\n            }\n\n            databaseStore.persistOrUpdateFriendData(friendData1);\n\n            if (request.getStatus() != 2) {\n                FriendData friendData2 = null;\n\n                friendDatas = friendsMap.get(request.getTargetUid());\n                if (friendDatas == null || friendDatas.size() == 0) {\n                    friendDatas = loadFriend(friendsMap, request.getTargetUid());\n                }\n                for (FriendData fd : friendDatas) {\n                    if (fd.getFriendUid().equals(userId)) {\n                        friendData2 = fd;\n                        break;\n                    }\n                }\n                if (friendData2 == null) {\n                    friendData2 = new FriendData(request.getTargetUid(), userId, \"\", request.getExtra(), request.getStatus(), 0, friendData1.getTimestamp());\n                } else {\n                    friendsMap.remove(request.getTargetUid(), friendData2);\n                    friendData2.setState(request.getStatus());\n                    friendData2.setTimestamp(System.currentTimeMillis());\n                }\n\n                databaseStore.persistOrUpdateFriendData(friendData2);\n\n                heads[0] = friendData2.getTimestamp();\n            } else {\n                heads[0] = 0;\n            }\n            heads[1] = friendData1.getTimestamp();\n            friendsMap.remove(userId);\n            friendsMap.remove(request.getTargetUid());\n\n            callbackRelationEvent(userId, request.getTargetUid(), 0, request.getStatus() == 0?\"1\":\"0\");\n            return ErrorCode.ERROR_CODE_SUCCESS;\n        }\n\n        MultiMap<String, WFCMessage.FriendRequest> requestMap = hzInstance.getMultiMap(USER_FRIENDS_REQUEST);\n        Collection<WFCMessage.FriendRequest> requests = requestMap.get(userId);\n        if (requests == null || requests.size() == 0) {\n            requests = loadFriendRequest(requestMap, userId);\n        }\n\n        WFCMessage.FriendRequest existRequest = null;\n        for (WFCMessage.FriendRequest tmpRequest : requests) {\n            if (tmpRequest.getFromUid().equals(request.getTargetUid())) {\n                existRequest = tmpRequest;\n                break;\n            }\n        }\n\n        if (existRequest != null) {\n            if (!alreadyFriend && mFriendRequestExpiration > 0 && System.currentTimeMillis() - existRequest.getUpdateDt() > mFriendRequestExpiration) {\n                return ErrorCode.ERROR_CODE_FRIEND_REQUEST_EXPIRED;\n            } else {\n                existRequest = existRequest.toBuilder().setStatus(request.getStatus()).setUpdateDt(System.currentTimeMillis()).build();\n                heads[2] = existRequest.getUpdateDt();\n                heads[3] = existRequest.getUpdateDt();\n                databaseStore.persistOrUpdateFriendRequest(existRequest);\n\n                if (request.getStatus() == ProtoConstants.FriendRequestStatus.RequestStatus_Accepted) {\n                    Collection<WFCMessage.FriendRequest> targetRequests = requestMap.get(request.getTargetUid());\n                    if (targetRequests == null || targetRequests.size() == 0) {\n                        targetRequests = loadFriendRequest(requestMap, request.getTargetUid());\n                    }\n\n                    WFCMessage.FriendRequest existTargetRequest = null;\n                    for (WFCMessage.FriendRequest tmpRequest : targetRequests) {\n                        if (tmpRequest.getFromUid().equals(userId)) {\n                            existTargetRequest = tmpRequest;\n                            break;\n                        }\n                    }\n\n                    if (existTargetRequest != null && existTargetRequest.getStatus() == ProtoConstants.FriendRequestStatus.RequestStatus_Sent) {\n                        existTargetRequest = existTargetRequest.toBuilder().setStatus(request.getStatus()).setUpdateDt(existRequest.getUpdateDt()).build();\n                        databaseStore.persistOrUpdateFriendRequest(existTargetRequest);\n                    }\n                }\n\n                if(!alreadyFriend && request.getStatus() == ProtoConstants.FriendRequestStatus.RequestStatus_Accepted){\n                    MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n                    FriendData friendData1 = new FriendData(userId, request.getTargetUid(), \"\", request.getExtra(), 0, 0, System.currentTimeMillis());\n                    databaseStore.persistOrUpdateFriendData(friendData1);\n\n                    FriendData friendData2 = new FriendData(request.getTargetUid(), userId, \"\", request.getExtra(), 0, 0, friendData1.getTimestamp());\n                    databaseStore.persistOrUpdateFriendData(friendData2);\n\n                    requestMap.remove(userId);\n                    requestMap.remove(request.getTargetUid());\n                    friendsMap.remove(userId);\n                    friendsMap.remove(request.getTargetUid());\n\n                    heads[0] = friendData2.getTimestamp();\n                    heads[1] = friendData1.getTimestamp();\n\n                    msgBuilder.setConversation(WFCMessage.Conversation.newBuilder().setTarget(userId).setLine(0).setType(ProtoConstants.ConversationType.ConversationType_Private).build());\n                    msgBuilder.setContent(WFCMessage.MessageContent.newBuilder().setType(1).setSearchableContent(existRequest.getReason()).build());\n\n                    callbackRelationEvent(userId, request.getTargetUid(), 0, \"1\");\n                }\n                if(alreadyFriend) {\n                    return ErrorCode.ERROR_CODE_ALREADY_FRIENDS;\n                }\n                return ErrorCode.ERROR_CODE_SUCCESS;\n            }\n        } else {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n    }\n\n    @Override\n    public ErrorCode blackUserRequest(String fromUser, String targetUserId, int state, long[] heads) {\n        if(state != 0 && state != 1 && state != 2){\n            return ErrorCode.INVALID_PARAMETER;\n        }\n\n        if (state == 2) {\n            state = 1;\n        } else {\n            state = 0;\n        }\n\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n\n        FriendData friendData = null;\n        Collection<FriendData> friends = friendsMap.get(fromUser);\n        if (friends == null || friends.size() == 0) {\n            friends = loadFriend(friendsMap, fromUser);\n        }\n\n        for (FriendData fd:friends) {\n            if (fd.getFriendUid().equals(targetUserId)) {\n                friendData = fd;\n                break;\n            }\n        }\n\n        if (friendData == null) {\n            friendData = new FriendData(fromUser, targetUserId, \"\", \"\", 1, state, System.currentTimeMillis());\n        }\n        friendData.setBlacked(state);\n        friendData.setTimestamp(System.currentTimeMillis());\n\n\n        databaseStore.persistOrUpdateFriendData(friendData);\n        friendsMap.remove(fromUser);\n\n        heads[0] = friendData.getTimestamp();\n\n        callbackRelationEvent(fromUser, targetUserId, 2, state+\"\");\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public FriendData getFriendData(String fromUser, String targetUserId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n\n        Collection<FriendData> friends = friendsMap.get(fromUser);\n        if (friends == null || friends.size() == 0) {\n            friends = loadFriend(friendsMap, fromUser);\n        }\n\n        for (FriendData fd:friends) {\n            if (fd.getFriendUid().equals(targetUserId)) {\n                return fd;\n            }\n        }\n\n        return null;\n    }\n\n    @Override\n    public ErrorCode setFriendAliasRequest(String fromUser, String targetUserId, String alias, long[] heads){\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n\n        FriendData friendData = null;\n        Collection<FriendData> friends = friendsMap.get(fromUser);\n        if (friends == null || friends.size() == 0) {\n            friends = loadFriend(friendsMap, fromUser);\n        }\n\n        for (FriendData fd:friends) {\n            if (fd.getFriendUid().equals(targetUserId)) {\n                friendData = fd;\n                break;\n            }\n        }\n\n        if (friendData == null) {\n            friendData = new FriendData();\n            friendData.setUserId(fromUser);\n            friendData.setFriendUid(targetUserId);\n        }\n\n        friendData.setAlias(alias);\n        friendData.setTimestamp(System.currentTimeMillis());\n\n        databaseStore.persistOrUpdateFriendData(friendData);\n\n        heads[0] = friendData.getTimestamp();\n\n        friendsMap.remove(fromUser);\n\n        callbackRelationEvent(fromUser, targetUserId, 1, alias);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode setFriendExtraRequest(String fromUser, String targetUserId, String extra, long[] heads){\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n\n        FriendData friendData = null;\n        Collection<FriendData> friends = friendsMap.get(fromUser);\n        if (friends == null || friends.size() == 0) {\n            friends = loadFriend(friendsMap, fromUser);\n        }\n\n        for (FriendData fd:friends) {\n            if (fd.getFriendUid().equals(targetUserId)) {\n                friendData = fd;\n                break;\n            }\n        }\n\n        if (friendData == null) {\n            friendData = new FriendData();\n            friendData.setUserId(fromUser);\n            friendData.setFriendUid(targetUserId);\n        }\n\n        friendData.setExtra(extra);\n        friendData.setTimestamp(System.currentTimeMillis());\n\n        databaseStore.persistOrUpdateFriendData(friendData);\n\n        heads[0] = friendData.getTimestamp();\n\n        friendsMap.remove(fromUser);\n\n        callbackRelationEvent(fromUser, targetUserId, 3, extra);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public boolean isAllowName(String name) {\n        if(StringUtil.isNullOrEmpty(name)) {\n            return true;\n        }\n\n        name = name.trim();\n        SystemSettingPojo notAllowNameSetting = getSystemSetting(ProtoConstants.SystemSettingType.NOT_ALLOW_USER_NAMES);\n        if (notAllowNameSetting != null && !StringUtil.isNullOrEmpty(notAllowNameSetting.value)) {\n            String[] ss = notAllowNameSetting.value.split(\",\");\n            for (String s : ss) {\n                if(name.contains(s.trim())) {\n                    return false;\n                }\n            }\n        }\n        return true;\n    }\n\n    @Override\n    public ErrorCode handleJoinChatroom(String userId, String clientId, String chatroomId) {\n        IMap<String, WFCMessage.ChatroomInfo> chatroomInfoMap = m_Server.getHazelcastInstance().getMap(CHATROOMS);\n        if (chatroomInfoMap == null || chatroomInfoMap.get(chatroomId) == null || chatroomInfoMap.get(chatroomId).getState() == ProtoConstants.ChatroomState.Chatroom_State_End) {\n            if(mChatroomCreateWhenNotExist) {\n                WFCMessage.ChatroomInfo.Builder builder = WFCMessage.ChatroomInfo.newBuilder().setTitle(chatroomId);\n                createChatroom(chatroomId, builder.build());\n            } else {\n                return ErrorCode.ERROR_CODE_NOT_EXIST;\n            }\n        }\n\n        MultiMap<String, UserClientEntry> chatroomMembers = m_Server.getHazelcastInstance().getMultiMap(CHATROOM_MEMBER_IDS);\n        String alreadyInChatroom = (String) m_Server.getHazelcastInstance().getMap(USER_CHATROOM).get(userId);\n        if(alreadyInChatroom != null) {\n            for (UserClientEntry userClientEntry : chatroomMembers.get(alreadyInChatroom)) {\n                if(userClientEntry.userId.equals(userId)) {\n                    if(!chatroomId.equals(alreadyInChatroom) || !userClientEntry.clientId.equals(clientId)) {\n                        if(mChatroomKickoffOtherPlatform) {\n                            handleQuitChatroom(userId, userClientEntry.clientId, chatroomId);\n                        } else {\n                            return ErrorCode.ERROR_CODE_OTHER_CLIENT_ALREADY_IN_CHATROOM;\n                        }\n                    }\n                }\n            }\n        }\n\n        m_Server.getStore().sessionsStore().getSession(clientId).refreshLastChatroomActiveTime();\n        m_Server.getHazelcastInstance().getMap(USER_CHATROOM).put(userId, chatroomId);\n        chatroomMembers.put(chatroomId, new UserClientEntry(userId, clientId));\n\n        mWriteLock.lock();\n        chatroomMessages.put(userId, new TreeMap<>());\n        mWriteLock.unlock();\n\n        callbackChatroomMemberEvent(userId, chatroomId, Arrays.asList(userId), Chatroom_Member_Event_Join);\n\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode handleQuitChatroom(String userId, String clientId, String chatroomId) {\n        m_Server.getHazelcastInstance().getMap(USER_CHATROOM).remove(userId);\n        m_Server.getHazelcastInstance().getMultiMap(CHATROOM_MEMBER_IDS).remove(chatroomId, new UserClientEntry(userId, clientId));\n\n        mWriteLock.lock();\n        chatroomMessages.remove(userId);\n        mWriteLock.unlock();\n\n        callbackChatroomMemberEvent(userId, chatroomId, Arrays.asList(userId), Chatroom_Member_Event_Leave);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public boolean checkChatroomParticipantIdelTime(MemorySessionStore.Session session) {\n        if (session == null) {\n            return false;\n        }\n\n        if(mChatroomParticipantIdleTime > 0 && System.currentTimeMillis() - session.getLastChatroomActiveTime() > mChatroomParticipantIdleTime) {\n            return false;\n        }\n        return true;\n    }\n\n    private String ensureSecretLength(String secret) {\n        while ( secret.length() < AES.keyLen) {\n            secret += \"w\";\n            secret += secret;\n        }\n        return secret;\n    }\n\n\n    @Override\n    public String getApplicationAuthCode(String fromUser, String applicationId, int type, String host) {\n        String secret = null;\n        if(type == ProtoConstants.ApplicationType.ApplicationType_Robot) {\n            WFCMessage.Robot robotData = getRobot(applicationId);\n            if(robotData != null && !StringUtil.isNullOrEmpty(robotData.getCallback()) && !StringUtil.isNullOrEmpty(robotData.getSecret())) {\n                try {\n                    URL url = new URL(robotData.getCallback());\n                    if(url.getHost() == null) {\n                        LOG.error(\"get application auth code error, application callback is invalid url\");\n                    } else if(url.getHost().equals(host)) {\n                        secret = robotData.getSecret();\n                    } else {\n                        LOG.error(\"get application auth code error, request host is not the same host with callback host\");\n                    }\n                } catch (MalformedURLException e) {\n                    e.printStackTrace();\n                }\n            } else {\n                String errorReason;\n                if(robotData == null) {\n                    errorReason = \"Robot not exist.\";\n                } else if(StringUtil.isNullOrEmpty(robotData.getCallback())) {\n                    errorReason = \"Robot no callback address\";\n                } else {\n                    errorReason = \"Robot no secret\";\n                }\n                LOG.warn(\"get application auth code error, reason {}\", errorReason);\n            }\n        } else if(type == ProtoConstants.ApplicationType.ApplicationType_Channel) {\n            WFCMessage.ChannelInfo channelData = getChannelInfo(applicationId);\n            if(channelData != null && !StringUtil.isNullOrEmpty(channelData.getCallback()) && !StringUtil.isNullOrEmpty(channelData.getSecret())) {\n                try {\n                    URL url = new URL(channelData.getCallback());\n                    if(url.getHost() == null) {\n                        LOG.error(\"get application auth code error, application callback is invalid url\");\n                    } else if(url.getHost().equals(host)) {\n                        secret = channelData.getSecret();\n                    } else {\n                        LOG.error(\"get application auth code error, request host is not the same host with callback host\");\n                    }\n                } catch (MalformedURLException e) {\n                    e.printStackTrace();\n                }\n            } else {\n                String errorReason;\n                if(channelData == null) {\n                    errorReason = \"Channel not exist.\";\n                } else if(StringUtil.isNullOrEmpty(channelData.getCallback())) {\n                    errorReason = \"Channel no callback address\";\n                } else {\n                    errorReason = \"Channel no secret\";\n                }\n                LOG.warn(\"get application auth code error, reason {}\", errorReason);\n            }\n        } else if(type == ProtoConstants.ApplicationType.ApplicationType_Admin) {\n            secret = AdminAction.getSecretKey();\n            applicationId = \"wfadmin\";\n        }\n\n        if(!StringUtil.isNullOrEmpty(secret)) {\n            secret = ensureSecretLength(secret);\n            byte[] token = AES.AESEncrypt(fromUser + \"?|?\" + System.currentTimeMillis() + \"?|?\" + applicationId + \"?|?\" + type, secret);\n            return new String(Base64.getEncoder().encode(token));\n        }\n\n        return null;\n    }\n\n    @Override\n    public String verifyApplicationAuthCode(String authCode, String applicationId, int type) {\n        String secret = null;\n        if(type == ProtoConstants.ApplicationType.ApplicationType_Robot) {\n            WFCMessage.Robot robotData = getRobot(applicationId);\n            if(robotData != null && !StringUtil.isNullOrEmpty(robotData.getCallback()) && !StringUtil.isNullOrEmpty(robotData.getSecret())) {\n                secret = robotData.getSecret();\n            }\n        } else if(type == ProtoConstants.ApplicationType.ApplicationType_Channel) {\n            WFCMessage.ChannelInfo channelData = getChannelInfo(applicationId);\n            if(channelData != null && !StringUtil.isNullOrEmpty(channelData.getCallback()) && !StringUtil.isNullOrEmpty(channelData.getSecret())) {\n                secret = channelData.getSecret();\n            }\n        } else if(type == ProtoConstants.ApplicationType.ApplicationType_Admin) {\n            secret = AdminAction.getSecretKey();\n            applicationId = \"wfadmin\";\n        }\n\n        secret = ensureSecretLength(secret);\n\n        byte[] data = Base64.getDecoder().decode(authCode);\n        data = AES.AESDecrypt(data, secret, true);\n\n        if (data == null || data.length == 0) {\n            return null;\n        } else {\n            String str = new String(data);\n            String[] strArr = str.split(\"\\\\?\\\\|\\\\?\");\n            if (strArr.length == 4) {\n                if (applicationId.equals(strArr[2])) {\n                    long timestamp= Long.parseLong(strArr[1]);\n                    if(System.currentTimeMillis() - timestamp > 60*1000) {\n                        return null;\n                    }\n                    return strArr[0];\n                }\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public ErrorCode configApplication(String appId, int appType, long timestamp, String nonce, String signature) {\n        String secret;\n        if(System.currentTimeMillis()/1000 - timestamp > 300) {\n            return ErrorCode.ERROR_CODE_SIGN_EXPIRED;\n        }\n\n        if(appType == ProtoConstants.ApplicationType.ApplicationType_Robot) {\n            WFCMessage.Robot robotData = getRobot(appId);\n            if(robotData != null) {\n                secret = robotData.getSecret();\n            } else {\n                return ErrorCode.ERROR_CODE_NOT_EXIST;\n            }\n        } else if(appType == ProtoConstants.ApplicationType.ApplicationType_Channel) {\n            WFCMessage.ChannelInfo channelData = getChannelInfo(appId);\n            if(channelData != null) {\n                secret = channelData.getSecret();\n            } else {\n                return ErrorCode.ERROR_CODE_NOT_EXIST;\n            }\n        } else {\n            LOG.error(\"Config application type only support 0 or 1\");\n            return ErrorCode.INVALID_PARAMETER;\n        }\n\n        String str = nonce + \"|\" + appId + \"|\" + timestamp + \"|\" + secret;\n        String sign = DigestUtils.sha1Hex(str);\n        if(sign.equals(signature)) {\n            return ErrorCode.ERROR_CODE_SUCCESS;\n        }\n\n        return ErrorCode.ERROR_CODE_AUTH_FAILURE;\n    }\n\n    @Override\n    public ErrorCode deleteFriend(String userId, String friendUid, long[] head) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n        Collection<FriendData> user1Friends = friendsMap.get(userId);\n        if (user1Friends == null || user1Friends.size() == 0) {\n            user1Friends = loadFriend(friendsMap, userId);\n        }\n        for (FriendData data :\n            user1Friends) {\n            if (data.getFriendUid().equals(friendUid)) {\n                long ts = System.currentTimeMillis();\n                head[0] = ts;\n                data.setState(1);\n                data.setTimestamp(ts);\n                databaseStore.persistOrUpdateFriendData(data);\n                break;\n            }\n        }\n\n        Collection<FriendData> user2Friends = friendsMap.get(friendUid);\n        if (user2Friends == null || user2Friends.size() == 0) {\n            user2Friends = loadFriend(friendsMap, friendUid);\n        }\n        for (FriendData data :\n            user2Friends) {\n            if (data.getFriendUid().equals(userId)) {\n                data.setState(1);\n                long ts = System.currentTimeMillis();\n                head[1] = ts;\n                data.setTimestamp(ts);\n                databaseStore.persistOrUpdateFriendData(data);\n                break;\n            }\n        }\n\n        friendsMap.remove(userId);\n        friendsMap.remove(friendUid);\n        callbackRelationEvent(userId, friendUid, 0, \"0\");\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode getUserSettings(String userId, long version, WFCMessage.GetUserSettingResult.Builder builder) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);\n        IMap<String, WFCMessage.GroupInfo> mGroups = hzInstance.getMap(GROUPS_MAP);\n        IMap<String, WFCMessage.ChannelInfo> mChannels = hzInstance.getMap(CHANNELS);\n\n        Collection<WFCMessage.UserSettingEntry> entries;\n        try {\n            mUserSettingLock.lock();\n            entries = userSettingMap.get(userId);\n            if (entries == null || entries.size() == 0) {\n                entries = loadPersistedUserSettings(userId, userSettingMap);\n            }\n        } finally {\n            mUserSettingLock.unlock();\n        }\n\n        ErrorCode ec = ErrorCode.ERROR_CODE_NOT_MODIFIED;\n        Calendar c = Calendar.getInstance();\n        c.setTime(new Date());\n        c.add(Calendar.MONTH, -1);\n        long monthAgo = c.getTimeInMillis();\n\n        if (entries != null) {\n            for (WFCMessage.UserSettingEntry entry : entries\n            ) {\n                if (entry.getUpdateDt() > version) {\n                    ec = ErrorCode.ERROR_CODE_SUCCESS;\n                    boolean skip = false;\n                    if (version == 0 && entry.getUpdateDt() > monthAgo) {\n                        if (entry.getScope() == UserSettingScope.kUserSettingConversationSync) {\n                            try {\n                                String key = entry.getKey();\n                                int pos1 = key.indexOf('-');\n                                String typeStr = key.substring(0, pos1);\n                                int type = Integer.parseInt(typeStr);\n                                if (type == ProtoConstants.ConversationType.ConversationType_Group\n                                    || type == ProtoConstants.ConversationType.ConversationType_Channel) {\n                                    int pos2 = key.indexOf('-', pos1 + 1);\n                                    String target = key.substring(pos2 + 1);\n\n                                    if (type == ProtoConstants.ConversationType.ConversationType_Group) {\n                                        WFCMessage.GroupInfo groupInfo = mGroups.get(target);\n                                        if (groupInfo == null) {\n                                            skip = true;\n                                        }\n                                    } else {\n                                        WFCMessage.ChannelInfo channelInfo = mChannels.get(target);\n                                        if (channelInfo == null) {\n                                            skip = true;\n                                        }\n                                    }\n                                }\n                            } catch (Exception e) {\n                                e.printStackTrace();\n                                Utility.printExecption(LOG, e);\n                            }\n\n                        }\n                    }\n\n                    if (!skip) {\n                        builder.addEntry(entry);\n                    }\n                }\n            }\n        }\n\n        if(mSyncDataPartSize > 0 && ec == ErrorCode.ERROR_CODE_SUCCESS && builder.getEntryCount() > mSyncDataPartSize) {\n            List<WFCMessage.UserSettingEntry> list = new ArrayList<>(builder.getEntryList());\n            list.sort(Comparator.comparingLong(WFCMessage.UserSettingEntry::getUpdateDt));\n            list = list.subList(0, mSyncDataPartSize);\n            builder.clearEntry().addAllEntry(list);\n        }\n        return ec;\n    }\n\n\n    private List<WFCMessage.UserSettingEntry> loadPersistedUserSettings(String userId, MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap) {\n        List<WFCMessage.UserSettingEntry> datas = databaseStore.getPersistUserSetting(userId);\n        for (WFCMessage.UserSettingEntry data : datas\n             ) {\n            userSettingMap.put(userId, data);\n        }\n        return datas;\n    }\n\n\n    @Override\n    public WFCMessage.UserSettingEntry getUserSetting(String userId, int scope, String key) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);\n\n        try {\n            mUserSettingLock.lock();\n            Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId);\n            if (entries == null || entries.size() == 0) {\n                entries = loadPersistedUserSettings(userId, userSettingMap);\n            }\n\n            if (entries != null) {\n                for (WFCMessage.UserSettingEntry entry : entries) {\n                    if (entry.getScope() == scope && (key== null || key.equals(entry.getKey()))) {\n                        return entry;\n                    }\n                }\n            }\n        } finally {\n            mUserSettingLock.unlock();\n        }\n\n        return null;\n    }\n\n    @Override\n    public List<WFCMessage.UserSettingEntry> getUserSetting(String userId, int scope) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);\n\n        List<WFCMessage.UserSettingEntry> result;\n        try {\n            mUserSettingLock.lock();\n            Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId);\n            if (entries == null || entries.size() == 0) {\n                entries = loadPersistedUserSettings(userId, userSettingMap);\n            }\n\n            result = new ArrayList<>();\n            if (entries != null) {\n                for (WFCMessage.UserSettingEntry entry : entries\n                ) {\n                    if (entry.getScope() == scope) {\n                        result.add(entry);\n                    }\n                }\n            }\n        } finally {\n            mUserSettingLock.unlock();\n        }\n\n        return result;\n    }\n\n    @Override\n    public long updateUserSettings(String userId, WFCMessage.ModifyUserSettingReq request, String clientId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);\n\n        long updateDt = 0;\n        try {\n            mUserSettingLock.lock();\n            Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId);\n            if (entries == null || entries.size() == 0) {\n                entries = loadPersistedUserSettings(userId, userSettingMap);\n                if (entries == null) {\n                    entries = new ArrayList<>();\n                }\n            }\n\n            updateDt = System.currentTimeMillis();\n            WFCMessage.UserSettingEntry settingEntry = WFCMessage.UserSettingEntry.newBuilder().setScope(request.getScope()).setKey(request.getKey()).setValue(request.getValue()).setUpdateDt(updateDt).build();\n            databaseStore.persistUserSetting(userId, settingEntry);\n\n            for (WFCMessage.UserSettingEntry entry : entries\n                ) {\n                if (entry.getScope() == request.getScope() && entry.getKey().equals(request.getKey())) {\n                    userSettingMap.remove(userId, entry);\n                    userSettingMap.put(userId, settingEntry);\n                    break;\n                }\n            }\n\n            userSettingMap.put(userId, settingEntry);\n        } finally {\n            mUserSettingLock.unlock();\n        }\n\n        if(request.getScope() == UserSettingScope.kUserSettingConversationSilent) {\n            int firstSplit = request.getKey().indexOf(\"-\");\n            int type = Integer.parseInt(request.getKey().substring(0, firstSplit));\n            int secondSplit = request.getKey().indexOf(\"-\", firstSplit+1);\n            int line = Integer.parseInt(request.getKey().substring(firstSplit+1, secondSplit));\n            String target = request.getKey().substring(secondSplit+1);\n            String key = userId + \"|\" + type + \"|\" + target + \"|\" + line;\n            userConvSlientMap.remove(key);\n        } else if(request.getScope() == UserSettingScope.kUserSettingGlobalSilent) {\n            userGlobalSlientMap.remove(userId);\n        } else if(request.getScope() == UserSettingScope.kUserSettingVoipSilent) {\n            userVoipSlientMap.remove(userId);\n        } else if(request.getScope() == UserSettingScope.kUserSettingHiddenNotificationDetail) {\n            userPushHiddenDetail.remove(userId);\n        }\n        IMHandler.getPublisher().publishNotification(IMTopic.NotifyUserSettingTopic, userId, updateDt, clientId);\n        return updateDt;\n    }\n\n    @Override\n    public void clearUserSettings(String userId) {\n        databaseStore.clearUserSetting(userId);\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n\n        try {\n            mUserSettingLock.lock();\n            MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);\n            userSettingMap.remove(userId);\n        } finally {\n            mUserSettingLock.unlock();\n        }\n    }\n\n    @Override\n    public boolean isLocked(String userId, String clientId) {\n        WFCMessage.UserSettingEntry lockSetting = getUserSetting(userId, UserSettingScopeLockPC, clientId);\n        if(lockSetting != null && \"1\".equals(lockSetting.getValue())) {\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean getUserGlobalSilent(String userId) {\n        Boolean slient = userGlobalSlientMap.get(userId);\n        if (slient == null) {\n            WFCMessage.UserSettingEntry entry = getUserSetting(userId, UserSettingScope.kUserSettingGlobalSilent, null);\n            if (entry == null || !entry.getValue().equals(\"1\")) {\n                slient = false;\n            } else {\n                slient = true;\n            }\n            userGlobalSlientMap.put(userId, slient);\n        }\n        return slient;\n    }\n\n    @Override\n    public boolean getUserVoipSilent(String userId) {\n        Boolean slient = userVoipSlientMap.get(userId);\n        if (slient == null) {\n            WFCMessage.UserSettingEntry entry = getUserSetting(userId, UserSettingScope.kUserSettingVoipSilent, null);\n            if (entry == null || !entry.getValue().equals(\"1\")) {\n                slient = false;\n            } else {\n                slient = true;\n            }\n            userVoipSlientMap.put(userId, slient);\n        }\n        return slient;\n    }\n\n    @Override\n    public boolean getUserPushHiddenDetail(String userId) {\n        Boolean hidden = userPushHiddenDetail.get(userId);\n        if (hidden == null) {\n            WFCMessage.UserSettingEntry entry = getUserSetting(userId, UserSettingScope.kUserSettingHiddenNotificationDetail, null);\n            if (entry == null || !entry.getValue().equals(\"1\")) {\n                hidden = false;\n            } else {\n                hidden = true;\n            }\n            userPushHiddenDetail.put(userId, hidden);\n        }\n        return hidden;\n    }\n\n    @Override\n    public boolean getUserConversationSilent(String userId, WFCMessage.Conversation conversation) {\n        String key = userId + \"|\" + conversation.getType() + \"|\" + conversation.getTarget() + \"|\" + conversation.getLine();\n        Boolean slient = userConvSlientMap.get(key);\n        if (slient == null) {\n            String convSlientKey = conversation.getType() + \"-\" + conversation.getLine() + \"-\" + conversation.getTarget();\n            WFCMessage.UserSettingEntry entry = getUserSetting(userId, UserSettingScope.kUserSettingConversationSilent, convSlientKey);\n            if (entry == null || !entry.getValue().equals(\"1\")) {\n                slient = false;\n            } else {\n                slient = true;\n            }\n            userConvSlientMap.put(key, slient);\n        }\n        return slient;\n    }\n\n    @Override\n    public boolean getSilentWhenPcOnline(String userId) {\n        WFCMessage.UserSettingEntry entry = getUserSetting(userId, UserSettingScope.kUserSettingMuteWhenPCOnline, null);\n        if (entry != null && \"1\".equals(entry.getValue())) {\n            return !mMobileDefaultSilentWhenPCOnline;\n        } else {\n            return mMobileDefaultSilentWhenPCOnline;\n        }\n    }\n    private Date getTodayDate() {\n        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(\"GMT\"));\n        int year = calendar.get(Calendar.YEAR);\n        int month = calendar.get(Calendar.MONTH);\n        int day = calendar.get(Calendar.DATE);\n        calendar.set(year, month, day, 0, 0, 0);\n        return calendar.getTime();\n    }\n\n    @Override\n    public boolean isUserNoDisturbing(String userId) {\n        WFCMessage.UserSettingEntry entry = getUserSetting(userId, UserSettingScope.kUserSettingNoDisturbing, \"\");\n        if (entry != null && !StringUtil.isNullOrEmpty(entry.getValue())) {\n            String[] arr = entry.getValue().split(\"\\\\|\");\n\n            if (arr.length == 2) {\n                int nowMins = (int)((System.currentTimeMillis() - getTodayDate().getTime())/1000/60);\n                try {\n                    int startMins = Integer.parseInt(arr[0]);\n                    int endMins = Integer.parseInt(arr[1]);\n                    if (endMins > startMins) {\n                        if (endMins > nowMins && nowMins > startMins) {\n                            return true;\n                        }\n                    } else {\n                        if (endMins > nowMins || nowMins > startMins) {\n                            return true;\n                        }\n                    }\n                } catch (NumberFormatException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public ErrorCode createChannel(String operator, WFCMessage.ChannelInfo channelInfo) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.ChannelInfo> mIMap = hzInstance.getMap(CHANNELS);\n\n        mIMap.put(channelInfo.getTargetId(), channelInfo);\n\n        callbackChannelInfoUpdateEvent(operator, channelInfo.getTargetId(), Channel_Event_Create);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public void clearUserChannels(String userId) {\n        databaseStore.getUserChannels(userId).forEach(s -> listenChannel(userId, s, false));\n    }\n\n\n    @Override\n    public ErrorCode modifyChannelInfo(String operator, String channelId, int modifyType, String value) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.ChannelInfo> mIMap = hzInstance.getMap(CHANNELS);\n\n        WFCMessage.ChannelInfo oldInfo = mIMap.get(channelId);\n\n        if (oldInfo == null) {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n        if (oldInfo.getOwner() == null || !oldInfo.getOwner().equals(operator)) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n\n\n        WFCMessage.ChannelInfo.Builder newInfoBuilder = oldInfo.toBuilder();\n\n        if (modifyType == Modify_Channel_Name)\n            newInfoBuilder.setName(value);\n        else if(modifyType == Modify_Channel_Portrait)\n            newInfoBuilder.setPortrait(value);\n        else if(modifyType == Modify_Channel_Desc)\n            newInfoBuilder.setDesc(value);\n        else if(modifyType == Modify_Channel_Extra)\n            newInfoBuilder.setExtra(value);\n        else if(modifyType == Modify_Channel_Secret)\n            newInfoBuilder.setSecret(value);\n        else if(modifyType == Modify_Channel_Callback)\n            newInfoBuilder.setCallback(value);\n        else if(modifyType == Modify_Channel_OnlyCallback) {\n            try {\n                newInfoBuilder.setAutomatic(Integer.parseInt(value));\n            } catch (Exception e) {\n                e.printStackTrace();\n                Utility.printExecption(LOG, e);\n            }\n        } else if(modifyType == Modify_Channel_Menu) {\n            OutputGetChannelInfo.OutputMenuList outputMenuButtons = GsonUtil.gson.fromJson(value, OutputGetChannelInfo.OutputMenuList.class);\n            if (!outputMenuButtons.isEmpty()) {\n                for (PojoChannelMenu outputMenuButton : outputMenuButtons) {\n                    newInfoBuilder.addMenu(outputMenuButton.toPbInfo());\n                }\n            }\n        }\n\n        newInfoBuilder.setUpdateDt(System.currentTimeMillis());\n        mIMap.put(channelId, newInfoBuilder.build());\n        callbackChannelInfoUpdateEvent(operator, channelId, Channel_Event_Update);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n\n    @Override\n    public ErrorCode transferChannel(String operator, String channelId, String newOwner) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.ChannelInfo> mIMap = hzInstance.getMap(CHANNELS);\n\n        WFCMessage.ChannelInfo oldInfo = mIMap.get(channelId);\n\n        if (oldInfo == null) {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n        if (oldInfo.getOwner() == null || !oldInfo.getOwner().equals(operator)) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n\n\n        WFCMessage.ChannelInfo.Builder newInfoBuilder = oldInfo.toBuilder();\n\n        newInfoBuilder.setOwner(newOwner);\n        newInfoBuilder.setUpdateDt(System.currentTimeMillis());\n        mIMap.put(channelId, newInfoBuilder.build());\n\n        callbackChannelInfoUpdateEvent(operator, channelId, Channel_Event_Transfer);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ErrorCode destroyChannel(String operator, String channelId, boolean isAdmin) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.ChannelInfo> mIMap = hzInstance.getMap(CHANNELS);\n\n        WFCMessage.ChannelInfo oldInfo = mIMap.get(channelId);\n\n        if (oldInfo == null) {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n        if ((oldInfo.getOwner() == null || !oldInfo.getOwner().equals(operator)) && !isAdmin) {\n            return ErrorCode.ERROR_CODE_NOT_RIGHT;\n        }\n\n\n        WFCMessage.ChannelInfo.Builder newInfoBuilder = oldInfo.toBuilder();\n\n        newInfoBuilder.setStatus(oldInfo.getStatus() | Channel_State_Mask_Deleted);\n        newInfoBuilder.setUpdateDt(System.currentTimeMillis());\n        mIMap.put(channelId, newInfoBuilder.build());\n        databaseStore.clearChannelListener(channelId);\n        hzInstance.getMultiMap(CHANNEL_LISTENERS).remove(channelId);\n\n        callbackChannelInfoUpdateEvent(operator, channelId, Channel_Event_Destroy);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public List<WFCMessage.ChannelInfo> searchChannel(String keyword, boolean buzzy, int page) {\n        return databaseStore.searchChannelFromDB(keyword, buzzy, page);\n    }\n\n\n    @Override\n    public List<String> getListenedChannels(String userId) {\n        return databaseStore.getUserChannels(userId);\n    }\n    @Override\n    public ErrorCode listenChannel(String operator, String channelId, boolean listen) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, String> listeners = hzInstance.getMultiMap(CHANNEL_LISTENERS);\n        IMap<String, WFCMessage.ChannelInfo> mIMap = hzInstance.getMap(CHANNELS);\n        WFCMessage.ChannelInfo channelInfo = mIMap.get(channelId);\n        if(channelInfo != null && (channelInfo.getStatus() & ProtoConstants.ChannelState.Channel_State_Mask_Private) > 0) {\n            return ErrorCode.ERROR_CODE_NOT_EXIST;\n        }\n\n        try {\n            mWriteLock.lock();\n            databaseStore.updateChannelListener(channelId, operator, listen);\n            listeners.remove(channelId);\n        } finally {\n            mWriteLock.unlock();\n        }\n        \n        IMHandler.getPublisher().notifyChannelListenStatusChanged(channelInfo, operator, listen);\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    private Collection<String> getChannelListener(String channelId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, String> listeners = hzInstance.getMultiMap(CHANNEL_LISTENERS);\n        Collection<String> result = listeners.get(channelId);\n        if (result.isEmpty()) {\n            try {\n                mWriteLock.lock();\n                result = databaseStore.getChannelListener(channelId);\n                for (String userId : result) {\n                    listeners.put(channelId, userId);\n                }\n            } finally {\n                mWriteLock.unlock();\n            }\n        }\n        return result;\n    }\n\n    @Override\n    public WFCMessage.ChannelInfo getChannelInfo(String channelId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<String, WFCMessage.ChannelInfo> mIMap = hzInstance.getMap(CHANNELS);\n        return mIMap.get(channelId);\n    }\n\n    @Override\n    public boolean canSendMessageInChannel(String user, String channelId) {\n        IMap<String, WFCMessage.ChannelInfo> mIMap = m_Server.getHazelcastInstance().getMap(CHANNELS);\n        WFCMessage.ChannelInfo info = mIMap.get(channelId);\n        if(info == null || info.getStatus() == Channel_State_Mask_Deleted) {\n            return false;\n        }\n        if(user.equals(info.getOwner())) {\n            return true;\n        }\n\n        if((info.getStatus() & Channel_State_Mask_Global) > 0 || (info.getStatus() & Channel_State_Mask_Message_Unsubscribed) > 0) {\n            return true;\n        }\n\n        Collection<String> channelMembers = getChannelListener(channelId);\n        if (channelMembers == null || !channelMembers.contains(user)) {\n            return false;\n        }\n\n        return true;\n    }\n\n    @Override\n    public boolean checkUserInChannel(String user, String channelId) {\n        Collection<String> channelMembers = getChannelListener(channelId);\n        if (channelMembers == null) {\n            return false;\n        }\n\n        if(!channelMembers.contains(user)) {\n            IMap<String, WFCMessage.ChannelInfo> mIMap = m_Server.getHazelcastInstance().getMap(CHANNELS);\n            WFCMessage.ChannelInfo info = mIMap.get(channelId);\n            if (info == null || !info.getOwner().equals(user)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    @Override\n    public Collection<String> getChannelSubscriber(String channelId) {\n        return getChannelListener(channelId);\n    }\n\n    @Override\n    public int getOnlineUserCount() {\n        return m_Server.getProcessor().getConnectionDescriptors().getActiveConnectionsNo();\n    }\n\n    @Override\n    public GetOnlineUserResult getOnlineUsers(int offset, int count) {\n        List<String> onlineUserIds = new ArrayList<>(m_Server.getProcessor().getConnectionDescriptors().getConnectedClientIds());\n        GetOnlineUserResult result = new GetOnlineUserResult();\n        result.userClients = new ArrayList<>();\n        result.totalCount = onlineUserIds.size();\n        result.offset = offset;\n\n        if(onlineUserIds.size() > offset) {\n            List<String> clientIds = onlineUserIds.subList(offset, Math.min(offset+count, onlineUserIds.size()));\n            for (String clientId : clientIds) {\n                MemorySessionStore.Session session = m_Server.getStore().sessionsStore().getSession(clientId);\n                if(session != null) {\n                    GetOnlineUserResult.UserClient userClient = new GetOnlineUserResult.UserClient();\n                    userClient.userId = session.getUsername();\n                    userClient.clientId = session.getClientID();\n                    userClient.platform = session.getPlatform();\n                    result.userClients.add(userClient);\n                }\n            }\n        }\n        return result;\n    }\n\n    @Override\n    public Set<String> handleSensitiveWord(String message) {\n        updateSensitiveWord();\n        return mSensitiveFilter.getSensitiveWords(message, SensitiveFilter.MatchType.MAX_MATCH);\n    }\n\n    @Override\n    public boolean addSensitiveWords(List<String> words) {\n        for (String word :\n            words) {\n            databaseStore.persistSensitiveWord(word.toLowerCase());\n        }\n        lastUpdateSensitiveTime = 0;\n        return true;\n    }\n\n    @Override\n    public boolean removeSensitiveWords(List<String> words) {\n        for (String word :\n            words) {\n            databaseStore.deleteSensitiveWord(word);\n        }\n        lastUpdateSensitiveTime = 0;\n        return true;\n    }\n\n    @Override\n    public List<String> getAllSensitiveWords() {\n        return new ArrayList<>(databaseStore.getSensitiveWord());\n    }\n\n    @Override\n    public boolean isSensitiveOnlyMessage() {\n        return mSensitiveOnlyMessage;\n    }\n\n    @Override\n    public WFCMessage.Message getMessage(long messageId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        IMap<Long, MessageBundle> mIMap = hzInstance.getMap(MESSAGES_MAP);\n        MessageBundle bundle = mIMap.get(messageId);\n        if (bundle != null) {\n            return bundle.getMessage();\n        }\n        return null;\n    }\n\n    @Override\n    public boolean isAllowClientCustomGroupNotification() {\n        return mGroupAllowClientCustomOperationNotification;\n    }\n\n    @Override\n    public boolean isAllowRobotCustomGroupNotification() {\n        return mGroupAllowRobotCustomOperationNotification;\n    }\n\n    @Override\n    public int getVisibleQuitKickoffNotification() {\n        return mGroupVisibleQuitKickoffNotification;\n    }\n\n    @Override\n    public boolean isGroupAllowPartSuccess() {\n        return mGroupAllowPartSuccess;\n    }\n\n    @Override\n    public int getGroupForbiddenClientOperation() {\n        return mGroupForbiddenClientOperation;\n    }\n\n    @Override\n    public boolean isForwardMessageWithClientInfo() {\n        return mForwardMessageWithClientInfo;\n    }\n\n    @Override\n    public boolean isForwardMessageWithSenderInfo() {\n        return mForwardMessageWithSenderInfo;\n    }\n\n    @Override\n    public boolean isForwardMessageWithTargetInfo() {\n        return mForwardMessageWithTargetInfo;\n    }\n\n    @Override\n    public boolean isRobotCallbackWithClientInfo() {\n        return mRobotCallbackWithClientInfo;\n    }\n\n    @Override\n    public boolean isRobotCallbackWithSenderInfo() {\n        return mRobotCallbackWithSenderInfo;\n    }\n\n    @Override\n    public boolean isRobotCallbackWithTargetInfo() {\n        return mRobotCallbackWithTargetInfo;\n    }\n\n    @Override\n    public boolean isRobotMentionExternalRobot() {\n        return mRobotMentionExternalRobot;\n    }\n\n    @Override\n    public int getRobotGetUserInfoMask() {\n        return mRobotGetUserInfoMask;\n    }\n\n    @Override\n    public boolean isChannelCallbackWithClientInfo() {\n        return mChannelCallbackWithClientInfo;\n    }\n\n    @Override\n    public boolean isChannelCallbackWithSenderInfo() {\n        return mChannelCallbackWithSenderInfo;\n    }\n\n    @Override\n    public boolean isChannelCallbackWithTargetInfo() {\n        return mChannelCallbackWithTargetInfo;\n    }\n\n    @Override\n    public boolean isChannelNewCallbackFeature() {\n        return mChannelNewCallbackFeature;\n    }\n\n    @Override\n    public boolean isRobotAutoAcceptFriendRequest() {\n        return mFriendRobotAutoAccept;\n    }\n\n    @Override\n    public long getPushExpiredTimes() {\n        return mPushExpiredTimes;\n    }\n\n    @Override\n    public Set<Integer> getForcePushTypes() {\n        return mForcePushTypes;\n    }\n\n    @Override\n    public List<Integer> getClientForbiddenSendTypes() {\n        return mForbiddenClientSendTypes;\n    }\n\n    @Override\n    public List<Integer> getBlackListExceptionTypes() {\n        return mBlackListExceptionTypes;\n    }\n\n    @Override\n    public List<Integer> getGroupMuteExceptionTypes() {\n        return mGroupMuteExceptionTypes;\n    }\n\n    @Override\n    public List<Integer> getGlobalMuteExceptionTypes() {\n        return mGlobalMuteExceptionTypes;\n    }\n\n    @Override\n    public long getMessageHead(String user) {\n        TreeMap<Long, Long> maps = userMessages.get(user);\n        if (maps == null) {\n            loadUserMessages(user);\n        }\n\n        mReadLock.lock();\n        try {\n            maps = userMessages.get(user);\n            Map.Entry<Long, Long> lastEntry = maps.lastEntry();\n            if (lastEntry != null) {\n                return lastEntry.getKey();\n            }\n        } finally {\n            mReadLock.unlock();\n        }\n        return 0;\n    }\n\n    private void loadUserMessages(String user) {\n        mWriteLock.lock();\n        try {\n            TreeMap<Long, Long> maps = userMessages.get(user);\n            if (maps == null) {\n                maps = databaseStore.reloadUserMessageMaps(user);\n                userMessages.put(user, maps);\n            }\n        } finally {\n            mWriteLock.unlock();\n        }\n    }\n\n    @Override\n    public long getFriendHead(String userId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, FriendData> friendsMap = hzInstance.getMultiMap(USER_FRIENDS);\n        Collection<FriendData> friends = friendsMap.get(userId);\n        if (friends == null || friends.size() == 0) {\n            friends = loadFriend(friendsMap, userId);\n        }\n        long max = 0;\n        if (friends != null && friends.size() > 0) {\n            for (FriendData friend :\n                friends) {\n                if (friend.getTimestamp() > max)\n                    max = friend.getTimestamp();\n            }\n        }\n\n        return max;\n    }\n\n    @Override\n    public long getFriendRqHead(String userId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, WFCMessage.FriendRequest> friendsReqMap = hzInstance.getMultiMap(USER_FRIENDS_REQUEST);\n        Collection<WFCMessage.FriendRequest> friendsReq = friendsReqMap.get(userId);\n        long max = 0;\n        if (friendsReq == null || friendsReq.size() == 0) {\n            friendsReq = loadFriendRequest(friendsReqMap, userId);\n        }\n\n        if (friendsReq != null && friendsReq.size() > 0) {\n            for (WFCMessage.FriendRequest request :\n                friendsReq) {\n                if (request.getUpdateDt() > max)\n                    max = request.getUpdateDt();\n            }\n        }\n\n        return max;\n    }\n\n    @Override\n    public long getSettingHead(String userId) {\n        HazelcastInstance hzInstance = m_Server.getHazelcastInstance();\n        MultiMap<String, WFCMessage.UserSettingEntry> userSettingMap = hzInstance.getMultiMap(USER_SETTING);\n\n        Collection<WFCMessage.UserSettingEntry> entries = userSettingMap.get(userId);\n        if (entries == null || entries.size() == 0) {\n            return 0L;\n        }\n\n        long max = 0;\n        for (WFCMessage.UserSettingEntry entry : entries\n            ) {\n            if (entry.getUpdateDt() > max) {\n                max = entry.getUpdateDt();\n            }\n        }\n\n        return max;\n    }\n\n\n    @Override\n    public String getShortUUID(){\n        if(!mIDUseUUID) {\n            int id = databaseStore.getGeneratedId();\n            if (id > 0) {\n                return IDUtils.toUid(id);\n            }\n        }\n        return UUIDGenerator.getUUID();\n    }\n\n    @Override\n    public boolean checkSignature(String signature) {\n        if(mClientSignatureSet.isEmpty()) {\n            return true;\n        }\n\n        if(StringUtil.isNullOrEmptyAfterTrim(signature)) {\n            if(mRejectEmptySignature) {\n                LOG.info(\"Failed check signature, no signature\");\n                return false;\n            } else {\n                return true;\n            }\n        } else {\n            if(mClientSignatureSet.contains(signature)) {\n                return true;\n            } else {\n                LOG.info(\"Failed check signature, signature no matched\");\n                return false;\n            }\n        }\n    }\n\n    @Override\n    public boolean existSignatures() {\n        return !mClientSignatureSet.isEmpty();\n    }\n\n    @Override\n    public void storeRetained(Topic topic, StoredMessage storedMessage) {\n        LOG.debug(\"Store retained message for topic={}, CId={}\", topic, storedMessage.getClientID());\n        if (storedMessage.getClientID() == null) {\n            throw new IllegalArgumentException(\"Message to be persisted must have a not null client ID\");\n        }\n        m_retainedStore.put(topic, storedMessage);\n    }\n\n    @Override\n    public Collection<StoredMessage> searchMatching(IMatchingCondition condition) {\n        LOG.debug(\"searchMatching scanning all retained messages, presents are {}\", m_retainedStore.size());\n\n        List<StoredMessage> results = new ArrayList<>();\n\n        for (Map.Entry<Topic, StoredMessage> entry : m_retainedStore.entrySet()) {\n            StoredMessage storedMsg = entry.getValue();\n            if (condition.match(entry.getKey())) {\n                results.add(storedMsg);\n            }\n        }\n\n        return results;\n    }\n\n    @Override\n    public void cleanRetained(Topic topic) {\n        m_retainedStore.remove(topic);\n    }\n\n\n    public static String getName(int[] bytes) {\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < bytes.length; i++) {\n            char ch = (char)(bytes[i]+17);\n            sb.append(ch);\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/MemorySessionStore.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.persistence;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.BrokerConstants;\nimport io.moquette.server.Constants;\nimport io.moquette.server.Server;\nimport io.moquette.spi.ClientSession;\nimport io.moquette.spi.ISessionsStore;\nimport io.moquette.spi.IMessagesStore.StoredMessage;\nimport io.netty.handler.codec.mqtt.MqttVersion;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.Utility;\n\nimport java.util.*;\nimport java.util.concurrent.*;\n\npublic class MemorySessionStore implements ISessionsStore {\n    private static int dumy = 1;\n    private static final Logger LOG = LoggerFactory.getLogger(MemorySessionStore.class);\n\n    private boolean supportMultiEndpoint = false;\n    private boolean supportMultiPCEndpoint = false;\n    private boolean supportMultiPadEndpoint = false;\n    private boolean supportMultiWearableEndpoint = false;\n    private boolean supportMultiTVEndpoint = false;\n    private boolean clientSupportKickoff = false;\n\n    public static class Session implements Comparable<Session>{\n        final String clientID;\n        String username;\n        private String appName;\n        private String deviceToken;\n        private String voipDeviceToken;\n        private String secret;\n        private String dbSecret;\n\n        private long lastActiveTime;\n\n        private long lastChatroomActiveTime;\n\n        private volatile int unReceivedMsgs;\n\n        private int deleted;\n\n        private boolean pullHistoryMsg;\n        private String ip;\n\n        public int getDeleted() {\n            return deleted;\n        }\n\n        public void setDeleted(int deleted) {\n            this.deleted = deleted;\n        }\n\n        private MqttVersion mqttVersion = MqttVersion.MQTT_3_1_1;\n\n        public long getLastActiveTime() {\n            return lastActiveTime;\n        }\n\n        public long getLastChatroomActiveTime() {\n            return lastChatroomActiveTime;\n        }\n\n        public void refreshLastChatroomActiveTime() {\n            this.lastChatroomActiveTime = System.currentTimeMillis();\n        }\n\n        public void refreshLastActiveTime() {\n            this.lastActiveTime = System.currentTimeMillis();\n        }\n\n        public int getUnReceivedMsgs() {\n            return unReceivedMsgs;\n        }\n\n        public boolean isPcClient() {\n            return platform == ProtoConstants.Platform.Platform_Windows || platform == ProtoConstants.Platform.Platform_OSX || platform == ProtoConstants.Platform.Platform_LINUX;\n        }\n\n        public boolean isPadClient() {\n            return platform == ProtoConstants.Platform.Platform_iPad || platform == ProtoConstants.Platform.Platform_APad || platform == ProtoConstants.Platform.Platform_HarmonyPad;\n        }\n\n        public boolean isTVClient() {\n            return platform == ProtoConstants.Platform.Platform_AppleTV || platform == ProtoConstants.Platform.Platform_AndroidTV || platform == ProtoConstants.Platform.Platform_HarmonyTV;\n        }\n\n        public int getPushType() {\n            return pushType;\n        }\n\n        public void setPushType(int pushType) {\n            this.pushType = pushType;\n        }\n\n        public String getDeviceName() {\n            return deviceName;\n        }\n\n        public void setDeviceName(String deviceName) {\n            this.deviceName = deviceName;\n        }\n\n        public String getDeviceVersion() {\n            return deviceVersion;\n        }\n\n        public void setDeviceVersion(String deviceVersion) {\n            this.deviceVersion = deviceVersion;\n        }\n\n        public String getPhoneName() {\n            return phoneName;\n        }\n\n        public void setPhoneName(String phoneName) {\n            this.phoneName = phoneName;\n        }\n\n        public String getLanguage() {\n            return language;\n        }\n\n        public void setLanguage(String language) {\n            this.language = language;\n        }\n\n        public String getCarrierName() {\n            return carrierName;\n        }\n\n        public void setCarrierName(String carrierName) {\n            this.carrierName = carrierName;\n        }\n\n        public boolean isPullHistoryMsg() {\n            return pullHistoryMsg;\n        }\n\n        public void setPullHistoryMsg(boolean pullHistoryMsg) {\n            this.pullHistoryMsg = pullHistoryMsg;\n        }\n\n        public long getUpdateDt() {\n            return updateDt;\n        }\n\n        public void setUpdateDt(long updateDt) {\n            this.updateDt = updateDt;\n            if (this.lastActiveTime == 0) {\n                this.lastActiveTime = updateDt;\n            }\n        }\n\n        public String getIp() {\n            return ip;\n        }\n\n        public void setIp(String ip) {\n            this.ip = ip;\n        }\n\n        private int pushType;\n        private int platform;\n\n        private String deviceName;\n        private String deviceVersion;\n        private String phoneName;\n        private String language;\n        private String carrierName;\n        private long updateDt;\n\n        final ClientSession clientSession;\n        final BlockingQueue<StoredMessage> queue = new ArrayBlockingQueue<>(Constants.MAX_MESSAGE_QUEUE);\n        final Map<Integer, StoredMessage> secondPhaseStore = new ConcurrentHashMap<>();\n        final Map<Integer, StoredMessage> outboundFlightMessages =\n                Collections.synchronizedMap(new HashMap<Integer, StoredMessage>());\n        final Map<Integer, StoredMessage> inboundFlightMessages = new ConcurrentHashMap<>();\n\n        public Session(String username, String clientID, ClientSession clientSession) {\n            this.clientID = clientID;\n            this.clientSession = clientSession;\n            this.username = username;\n        }\n\n        public String getAppName() {\n            return appName;\n        }\n\n        public void setAppName(String appName) {\n            this.appName = appName;\n        }\n\n        public String getDeviceToken() {\n            return deviceToken;\n        }\n\n        public void setDeviceToken(String deviceToken) {\n            this.deviceToken = deviceToken;\n        }\n\n        public int getPlatform() {\n            return platform;\n        }\n\n        public void setPlatform(int platform) {\n            this.platform = platform;\n        }\n\n        public String getClientID() {\n\t\t\treturn clientID;\n\t\t}\n\n\t\tpublic String getUsername() {\n\t\t\treturn username;\n\t\t}\n\n        public void setUsername(String username) {\n            this.username = username;\n        }\n\n        public ClientSession getClientSession() {\n\t\t\treturn clientSession;\n\t\t}\n\n        public String getSecret() {\n            return secret;\n        }\n\n        public void setSecret(String secret) {\n            this.secret = secret;\n        }\n\n        public String getDbSecret() {\n            return dbSecret;\n        }\n\n        public void setDbSecret(String dbSecret) {\n            this.dbSecret = dbSecret;\n        }\n\n        public String getVoipDeviceToken() {\n            return voipDeviceToken;\n        }\n\n        public void setVoipDeviceToken(String voipDeviceToken) {\n            this.voipDeviceToken = voipDeviceToken;\n        }\n\n        @Override\n\t\tpublic int compareTo(Session o) {\n\t\t\t// TODO Auto-generated method stub\n\t\t\tif (clientID.equals(o.clientID) && username.equals(o.username)) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (clientID.equals(o.clientID)) {\n\t\t\t\treturn username.compareTo(o.username);\n\t\t\t} else {\n\t\t\t\treturn clientID.compareTo(o.clientID);\n\t\t\t}\n\t\t}\n\n\n        public MqttVersion getMqttVersion() {\n            return mqttVersion;\n        }\n\n        public void setMqttVersion(MqttVersion mqttVersion) {\n            this.mqttVersion = mqttVersion;\n        }\n    }\n\n    private final Map<String, Session> sessions = new ConcurrentHashMap<>();\n    private final Map<String, ConcurrentSkipListSet<String>> userSessions = new ConcurrentHashMap<>();\n\n    private final Server mServer;\n    private final DatabaseStore databaseStore;\n    public MemorySessionStore(Server server, DatabaseStore databaseStore) {\n        mServer = server;\n        this.databaseStore = databaseStore;\n\n        try {\n            supportMultiEndpoint = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.SERVER_MULTI_ENDPOINT, \"false\"));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        try {\n            supportMultiPCEndpoint = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.SERVER_MULTI_PC_ENDPOINT, \"false\"));\n        } catch (Exception e) {\n        }\n        try {\n            supportMultiPadEndpoint = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.SERVER_MULTI_PAD_ENDPOINT, \"false\"));\n        } catch (Exception e) {\n        }\n\n        try {\n            supportMultiWearableEndpoint = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.SERVER_MULTI_WEARABLE_ENDPOINT, \"false\"));\n        } catch (Exception e) {\n        }\n\n        try {\n            supportMultiTVEndpoint = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.SERVER_MULTI_TV_ENDPOINT, \"false\"));\n        } catch (Exception e) {\n        }\n\n        try {\n            clientSupportKickoff = Boolean.parseBoolean(server.getConfig().getProperty(BrokerConstants.SERVER_CLIENT_SUPPORT_KICKOFF_EVENT, \"false\"));\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n    }\n\n    @Override\n    public Session getSession(String clientID) {\n        if (StringUtil.isNullOrEmpty(clientID)) {\n            return null;\n        }\n        Session session = sessions.get(clientID);\n        if (session == null) {\n            LOG.error(\"Can't find the session for client <{}>\", clientID);\n        }\n        return session;\n    }\n\n    @Override\n    public void cleanDuplatedToken(String cid, int pushType, String token, boolean isVoip, String packageName) {\n        if (StringUtil.isNullOrEmpty(token) || isVoip) {\n            return;\n        }\n\n        Iterator<Map.Entry<String, Session>> it = sessions.entrySet().iterator();\n        while (it.hasNext()) {\n            Session session = it.next().getValue();\n            if (!session.getClientID().equals(cid) && (session.pushType == pushType && token.equals(session.deviceToken)) && (!StringUtil.isNullOrEmpty(packageName) && packageName.equals(session.getAppName()))) {\n                session.deviceToken = null;\n            }\n        }\n    }\n\n    @Override\n    public void initStore() {\n    }\n\n    @Override\n    public boolean contains(String clientID) {\n        return sessions.containsKey(clientID);\n    }\n\n    @Override\n    public void updateSessionToken(Session session, boolean voip) {\n        databaseStore.updateSessionToken(session.getUsername(), session.getClientID(), voip ? session.getVoipDeviceToken() : session.getDeviceToken(), session.getPushType(), voip);\n    }\n\n    @Override\n    public void clearUserSession(String username) {\n        LOG.info(\"Fooooooooo <{}>\", username);\n\n        databaseStore.clearUserSessions(username);\n\n        ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);\n        for (String clientID : sessionSet) {\n            Session s = sessions.remove(clientID);\n            mServer.getProcessor().kickoffSession(s);\n        }\n        userSessions.remove(username);\n    }\n\n    @Override\n    public Session updateOrCreateUserSession(String username, String clientID, int platform) {\n        LOG.debug(\"createUserSession for client <{}>, user <{}>\", clientID, username);\n\n        Session session = sessions.get(clientID);\n\n        if (session != null && !session.username.equals(username)) {\n            if (userSessions.get(session.username) != null) {\n                userSessions.get(session.username).remove(clientID);\n            }\n            session = null;\n        }\n        ClientSession clientSession = new ClientSession(clientID, this);\n        if(session == null) {\n            session = databaseStore.getSession(username, clientID, clientSession);\n            if (session == null) {\n                session = databaseStore.createSession(username, clientID, clientSession, platform);\n            }\n        }\n\n        sessions.put(clientID, session);\n        ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);\n        sessionSet.add(clientID);\n\n        if (session.getDeleted() > 0) {\n            session.setDeleted(0);\n            databaseStore.updateSessionDeleted(username, clientID, 0);\n        }\n\n        if (session.getPlatform() != platform) {\n            session.setPlatform(platform);\n            databaseStore.updateSessionPlatform(username, clientID, platform);\n        }\n        databaseStore.clearMultiUser(username, clientID);\n\n        if (!supportMultiEndpoint\n            && platform > 0\n            && !(platform == ProtoConstants.Platform.Platform_Windows && supportMultiPCEndpoint)\n            && !(platform == ProtoConstants.Platform.Platform_LINUX && supportMultiPCEndpoint)\n            && !(platform == ProtoConstants.Platform.Platform_OSX && supportMultiPCEndpoint)\n            && !(platform == ProtoConstants.Platform.Platform_HarmonyPC && supportMultiPCEndpoint)\n            && !(platform == ProtoConstants.Platform.Platform_iPad && supportMultiPadEndpoint)\n            && !(platform == ProtoConstants.Platform.Platform_APad && supportMultiPadEndpoint)\n            && !(platform == ProtoConstants.Platform.Platform_HarmonyPad && supportMultiPadEndpoint)\n            && !(platform == ProtoConstants.Platform.Platform_AndroidWearable && supportMultiWearableEndpoint)\n            && !(platform == ProtoConstants.Platform.Platform_HarmonyWearable && supportMultiWearableEndpoint)\n            && !(platform == ProtoConstants.Platform.Platform_AndroidTV && supportMultiTVEndpoint)\n            && !(platform == ProtoConstants.Platform.Platform_AppleTV && supportMultiTVEndpoint)\n            && !(platform == ProtoConstants.Platform.Platform_HarmonyTV && supportMultiTVEndpoint)\n        ) {\n            databaseStore.clearMultiEndpoint(username, clientID, platform);\n            if (userSessions.get(username) != null) {\n                Iterator<String> it = userSessions.get(username).iterator();\n                while (it.hasNext()) {\n                    String c = it.next();\n                    if (!clientID.equals(c)) {\n                        Session s = sessions.get(c);\n                        if (s == null) {\n                            it.remove();\n                            continue;\n                        }\n\n                        boolean remove = false;\n                        if (platform == ProtoConstants.Platform.Platform_Android || platform == ProtoConstants.Platform.Platform_iOS || platform == ProtoConstants.Platform.Platform_Harmony) {\n                            if (s.getPlatform() == ProtoConstants.Platform.Platform_Android || s.getPlatform() == ProtoConstants.Platform.Platform_iOS || s.getPlatform() == ProtoConstants.Platform.Platform_Harmony) {\n                                remove = true;\n                            }\n                        } else if(platform == ProtoConstants.Platform.Platform_iPad || platform == ProtoConstants.Platform.Platform_APad || platform == ProtoConstants.Platform.Platform_HarmonyPad) {\n                            if (s.getPlatform() == ProtoConstants.Platform.Platform_iPad || s.getPlatform() == ProtoConstants.Platform.Platform_APad || s.getPlatform() == ProtoConstants.Platform.Platform_HarmonyPad) {\n                                remove = true;\n                            }\n                        } else if(platform == ProtoConstants.Platform.Platform_OSX || platform == ProtoConstants.Platform.Platform_Windows || platform == ProtoConstants.Platform.Platform_LINUX || platform == ProtoConstants.Platform.Platform_HarmonyPC) {\n                            if (s.getPlatform() == ProtoConstants.Platform.Platform_OSX || s.getPlatform() == ProtoConstants.Platform.Platform_Windows || s.getPlatform() == ProtoConstants.Platform.Platform_LINUX || s.getPlatform() == ProtoConstants.Platform.Platform_HarmonyPC) {\n                                remove = true;\n                            }\n                        } else if(platform == ProtoConstants.Platform.Platform_AndroidWearable || platform == ProtoConstants.Platform.Platform_HarmonyWearable) {\n                            if (s.getPlatform() == ProtoConstants.Platform.Platform_AndroidWearable || s.getPlatform() == ProtoConstants.Platform.Platform_HarmonyWearable) {\n                                remove = true;\n                            }\n                        } else if(platform == ProtoConstants.Platform.Platform_AndroidTV || platform == ProtoConstants.Platform.Platform_AppleTV || platform == ProtoConstants.Platform.Platform_HarmonyTV) {\n                            if (s.getPlatform() == ProtoConstants.Platform.Platform_AndroidTV || s.getPlatform() == ProtoConstants.Platform.Platform_AppleTV || s.getPlatform() == ProtoConstants.Platform.Platform_HarmonyTV) {\n                                remove = true;\n                            }\n                        } else { //web, microapp\n                            if (s.getPlatform() ==platform) {\n                                remove = true;\n                            }\n                        }\n\n                        if (remove) {\n                            sessions.remove(c);\n                            it.remove();\n                            mServer.getProcessor().kickoffSession(s);\n                        }\n                    }\n                }\n            }\n\n        }\n\n        return session;\n    }\n\n    @Override\n    public void kickoffUserClient(String username, String cid) {\n        List<String> clientIds = new ArrayList<>();\n        if(StringUtil.isNullOrEmpty(cid)) {\n            ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);\n            clientIds.addAll(sessionSet);\n        } else {\n            clientIds.add(cid);\n        }\n\n        for (String clientID: clientIds) {\n            Session session = sessions.get(clientID);\n            if(session == null) {\n                ClientSession clientSession = new ClientSession(clientID, this);\n                session = databaseStore.getSession(username, clientID, clientSession);\n                if (session == null || session.getDeleted() > 0) {\n                    continue;\n                }\n                sessions.put(clientID, session);\n            }\n\n            if (session.getDeleted() == 0) {\n                session.setDeleted(1);\n                databaseStore.updateSessionDeleted(username, clientID, 1);\n                mServer.getProcessor().kickoffSession(session);\n            }\n        }\n    }\n\n    @Override\n    public ErrorCode loadActiveSession(String username, String clientID) {\n        LOG.debug(\"createNewSession for client <{}>\", clientID);\n\n        Session session = sessions.get(clientID);\n\n        if (session != null && session.getDeleted() == 0) {\n            LOG.error(\"already exists a session for client <{}>, bad condition\", clientID);\n            return ErrorCode.ERROR_CODE_SUCCESS;\n        }\n\n        if (session != null && session.getDeleted() > 0) {\n            if(clientSupportKickoff) {\n                return ErrorCode.ERROR_CODE_KICKED_OFF;\n            } else {\n                return ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH;\n            }\n        }\n\n        ClientSession clientSession = new ClientSession(clientID, this);\n        session = databaseStore.getSession(username, clientID, clientSession);\n\n        if (session == null) {\n            return ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH;\n        }\n\n        if(session.getDeleted() > 0) {\n            if(clientSupportKickoff) {\n                return ErrorCode.ERROR_CODE_KICKED_OFF;\n            } else {\n                return ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH;\n            }\n        }\n\n        sessions.put(clientID, session);\n        ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);\n        sessionSet.add(clientID);\n\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n    @Override\n    public ClientSession updateExistSession(String username, String clientID, WFCMessage.RouteRequest endpoint, boolean cleanSession) {\n        LOG.debug(\"updateExistSession for client <{}>\", clientID);\n        Session session = sessions.get(clientID);\n        if (session == null) {\n            LOG.error(\"already exists a session for client <{}>, bad condition\", clientID);\n            throw new IllegalArgumentException(\"Can't create a session with the ID of an already existing\" + clientID);\n        }\n        if (!session.getUsername().equals(username)) {\n            ConcurrentSkipListSet<String> sessionSet = userSessions.get(session.getUsername());\n            if(sessionSet != null) {\n                sessionSet.remove(clientID);\n            }\n        }\n\n        session.setUsername(username);\n        sessions.put(clientID, session);\n        ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);\n        sessionSet.add(clientID);\n\n        if (endpoint != null) {\n            databaseStore.updateSession(username, clientID, session, endpoint);\n        }\n\n        return session.clientSession;\n    }\n\n    @Override\n    public void updateSessionIp(String username, String clientID, String ip) {\n        Session session = getSession(clientID);\n        if(session != null && session.getDeleted() == 0) {\n            session.setIp(ip);\n            databaseStore.updateSessionIp(username, clientID, ip);\n        }\n    }\n\n    @Override\n    public Session sessionForClientAndUser(String username, String clientID) {\n        Session session = sessions.get(clientID);\n        if (session != null) {\n            if (session.getUsername().equals(username)) {\n                return session;\n            } else {\n                cleanSession(null, clientID);\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public ClientSession sessionForClient(String clientID) {\n        if (!sessions.containsKey(clientID)) {\n            LOG.error(\"Can't find the session for client <{}>\", clientID);\n            return null;\n        }\n\n        Session session = sessions.get(clientID);\n\n        return session.getClientSession();\n    }\n\n    @Override\n    public void loadUserSession(String username, String clientID) {\n        if (sessions.containsKey(clientID)) {\n            ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);\n            sessionSet.add(clientID);\n            return;\n        }\n        Session session = databaseStore.getSession(username, clientID, new ClientSession(clientID, this));\n        if (session != null) {\n            sessions.put(clientID, session);\n            ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);\n            sessionSet.add(clientID);\n        }\n    }\n\n    private ConcurrentSkipListSet<String> getUserSessionSet(String username) {\n        ConcurrentSkipListSet<String> sessionSet = userSessions.get(username);\n        if (sessionSet == null) {\n            sessionSet = new ConcurrentSkipListSet<String>();\n            List<Session> ss = databaseStore.getUserActivedSessions(username);\n            for (Session s : ss) {\n                sessionSet.add(s.getClientID());\n                sessions.put(s.getClientID(), s);\n            }\n            userSessions.put(username, sessionSet);\n        }\n\n        sessionSet = userSessions.get(username);\n        return sessionSet;\n    }\n\n    @Override\n    public Collection<Session> sessionForUser(String username) {\n    \tConcurrentSkipListSet<String> sessionSet = getUserSessionSet(username);\n\n        ArrayList<Session> out = new ArrayList<>();\n        for (String clientId : sessionSet\n             ) {\n            Session session = sessions.get(clientId);\n            if (session != null && session.getUsername().equals(username)) {\n                out.add(session);\n            }\n        }\n        return out;\n    }\n\n    @Override\n    public Collection<ClientSession> getAllSessions() {\n        Collection<ClientSession> result = new ArrayList<>();\n        for (Session entry : sessions.values()) {\n            result.add(new ClientSession(entry.clientID, this));\n        }\n        return result;\n    }\n\n    @Override\n    public boolean isClientOnline(String clientId) {\n        return mServer.getProcessor().getConnectionDescriptors().isConnected(clientId);\n    }\n\n    @Override\n    public StoredMessage inFlightAck(String clientID, int messageID) {\n        return getSession(clientID).outboundFlightMessages.remove(messageID);\n    }\n\n    @Override\n    public void inFlight(String clientID, int messageID, StoredMessage msg) {\n        Session session = sessions.get(clientID);\n        if (session == null) {\n            LOG.error(\"Can't find the session for client <{}>\", clientID);\n            return;\n        }\n\n        session.outboundFlightMessages.put(messageID, msg);\n    }\n\n    /**\n     * Return the next valid packetIdentifier for the given client session.\n     */\n    @Override\n    public int nextPacketID(String clientID) {\n        if (!sessions.containsKey(clientID)) {\n            LOG.error(\"Can't find the session for client <{}>\", clientID);\n            return -1;\n        }\n\n        Map<Integer, StoredMessage> m = sessions.get(clientID).outboundFlightMessages;\n        int maxId = m.keySet().isEmpty() ? 0 : Collections.max(m.keySet());\n        int nextPacketId = (maxId + 1) % 0xFFFF;\n        m.put(nextPacketId, null);\n        return nextPacketId;\n    }\n\n    @Override\n    public BlockingQueue<StoredMessage> queue(String clientID) {\n        if (!sessions.containsKey(clientID)) {\n            LOG.error(\"Can't find the session for client <{}>\", clientID);\n            return null;\n        }\n\n        return sessions.get(clientID).queue;\n    }\n\n    @Override\n    public void dropQueue(String clientID) {\n        if (sessions.get(clientID) != null) {\n            sessions.get(clientID).queue.clear();\n        }\n    }\n\n    @Override\n    public void moveInFlightToSecondPhaseAckWaiting(String clientID, int messageID, StoredMessage msg) {\n        LOG.info(\"Moving msg inflight second phase store, clientID <{}> messageID {}\", clientID, messageID);\n        Session session = sessions.get(clientID);\n        if (session == null) {\n            LOG.error(\"Can't find the session for client <{}>\", clientID);\n            return;\n        }\n\n        session.secondPhaseStore.put(messageID, msg);\n        session.outboundFlightMessages.put(messageID, msg);\n    }\n\n    @Override\n    public StoredMessage secondPhaseAcknowledged(String clientID, int messageID) {\n        LOG.info(\"Acknowledged message in second phase, clientID <{}> messageID {}\", clientID, messageID);\n        return getSession(clientID).secondPhaseStore.remove(messageID);\n    }\n\n    @Override\n    public int getInflightMessagesNo(String clientID) {\n        Session session = sessions.get(clientID);\n        if (session == null) {\n            LOG.error(\"Can't find the session for client <{}>\", clientID);\n            return 0;\n        }\n\n        return session.inboundFlightMessages.size() + session.secondPhaseStore.size()\n            + session.outboundFlightMessages.size();\n    }\n\n    @Override\n    public StoredMessage inboundInflight(String clientID, int messageID) {\n        return getSession(clientID).inboundFlightMessages.get(messageID);\n    }\n\n    @Override\n    public void markAsInboundInflight(String clientID, int messageID, StoredMessage msg) {\n        if (!sessions.containsKey(clientID))\n            LOG.error(\"Can't find the session for client <{}>\", clientID);\n\n        sessions.get(clientID).inboundFlightMessages.put(messageID, msg);\n    }\n\n    @Override\n    public int getPendingPublishMessagesNo(String clientID) {\n        if (!sessions.containsKey(clientID)) {\n            LOG.error(\"Can't find the session for client <{}>\", clientID);\n            return 0;\n        }\n\n        return sessions.get(clientID).queue.size();\n    }\n\n    @Override\n    public int getSecondPhaseAckPendingMessages(String clientID) {\n        if (!sessions.containsKey(clientID)) {\n            LOG.error(\"Can't find the session for client <{}>\", clientID);\n            return 0;\n        }\n\n        return sessions.get(clientID).secondPhaseStore.size();\n    }\n\n\n    @Override\n    public ErrorCode kickoffPCClient(String operator, String pcClientId) {\n        Session session = sessions.get(pcClientId);\n        if (session != null) {\n            if(!operator.equals(session.getUsername())) {\n                LOG.error(\"kickoffPCClient failure, user {} don't have client {}\", operator, pcClientId);\n                mServer.getProcessor().getMessagesStore().forceCleanOnlineStatus(operator, pcClientId);\n                return ErrorCode.ERROR_CODE_SUCCESS;\n            }\n            if (session.getPlatform() == ProtoConstants.Platform.Platform_LINUX\n                || session.getPlatform() == ProtoConstants.Platform.Platform_WEB\n                || session.getPlatform() == ProtoConstants.Platform.Platform_Windows\n                || session.getPlatform() == ProtoConstants.Platform.Platform_OSX\n                || session.getPlatform() == ProtoConstants.Platform.Platform_HarmonyPC\n                || session.getPlatform() == ProtoConstants.Platform.Platform_iPad\n                || session.getPlatform() == ProtoConstants.Platform.Platform_APad\n                || session.getPlatform() == ProtoConstants.Platform.Platform_HarmonyPad\n            ) {\n                databaseStore.updateSessionDeleted(operator, pcClientId, 1);\n                sessions.remove(pcClientId);\n                mServer.getProcessor().kickoffSession(session);\n            } else {\n                LOG.error(\"session {} is not pc client:{}\", pcClientId, session.getPlatform());\n                return ErrorCode.ERROR_CODE_NOT_RIGHT;\n            }\n        } else {\n            LOG.error(\"Can't find the session for client <{}>\", pcClientId);\n            mServer.getProcessor().getMessagesStore().forceCleanOnlineStatus(operator, pcClientId);\n        }\n        return ErrorCode.ERROR_CODE_SUCCESS;\n    }\n\n\n    @Override\n    public void disableSession(String userId, String clientId) {\n        Session session = sessions.get(clientId);\n        if (session != null && session.getDeleted() == 0 && (userId == null || session.getUsername().equals(userId))) {\n            mServer.getProcessor().processOffline(session, true, () -> {\n                databaseStore.updateSessionDeleted(session.getUsername(), clientId, 1);\n                ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(session.username);\n                sessionSet.remove(clientId);\n                sessions.remove(clientId);\n            });\n        }\n    }\n\n    @Override\n    public void cleanSession(String userId, String clientID) {\n        LOG.info(\"Fooooooooo <{}>\", clientID);\n\n        Session session = sessions.get(clientID);\n        if (session == null) {\n            LOG.error(\"Can't find the session for client <{}>\", clientID);\n            return;\n        }\n\n        if(userId != null && !session.getUsername().equals(userId)) {\n            return;\n        }\n\n        mServer.getProcessor().processOffline(session, true, () -> {\n            ConcurrentSkipListSet<String> sessionSet = getUserSessionSet(session.username);\n            sessionSet.remove(clientID);\n\n            // remove also the messages stored of type QoS1/2\n            LOG.info(\"Removing stored messages with QoS 1 and 2. ClientId={}\", clientID);\n\n            session.secondPhaseStore.clear();\n            session.outboundFlightMessages.clear();\n            session.inboundFlightMessages.clear();\n\n            LOG.info(\"Wiping existing subscriptions. ClientId={}\", clientID);\n\n            //remove also the enqueued messages\n            dropQueue(clientID);\n\n            // TODO this missing last step breaks the junit test\n            sessions.remove(clientID);\n        });\n    }\n    @Override\n    public boolean isMultiEndpointSupported() {\n        return supportMultiEndpoint;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/MemoryStorageService.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.persistence;\n\nimport cn.wildfirechat.server.ThreadPoolExecutorWrapper;\nimport io.moquette.server.Server;\nimport io.moquette.server.config.IConfig;\nimport io.moquette.spi.IMessagesStore;\nimport io.moquette.spi.ISessionsStore;\nimport io.moquette.spi.IStore;\n\nimport java.util.concurrent.ScheduledExecutorService;\n\npublic class MemoryStorageService implements IStore {\n\n    private MemorySessionStore m_sessionsStore;\n    private MemoryMessagesStore m_messagesStore;\n\n    public MemoryStorageService(IConfig props, ThreadPoolExecutorWrapper scheduler, Server server) {\n        DatabaseStore databaseStore = new DatabaseStore(scheduler);\n        m_messagesStore = new MemoryMessagesStore(server, databaseStore);\n        m_sessionsStore = new MemorySessionStore(server, databaseStore);\n    }\n\n    @Override\n    public IMessagesStore messagesStore() {\n        return m_messagesStore;\n    }\n\n    @Override\n    public ISessionsStore sessionsStore() {\n        return m_sessionsStore;\n    }\n\n    @Override\n    public void initStore() {\n        m_messagesStore.initStore();\n        m_sessionsStore.initStore();\n    }\n\n    @Override\n    public void close() {\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/MessageLoader.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.persistence;\n\nimport com.hazelcast.core.MapStore;\nimport io.moquette.server.Server;\nimport win.liyufan.im.MessageBundle;\n\nimport java.util.Collection;\nimport java.util.Map;\n\npublic class MessageLoader implements MapStore<Long, MessageBundle> {\n    private DatabaseStore getDatabaseStore() {\n        return Server.getServer().getStore().messagesStore().getDatabaseStore();\n    }\n    /**\n     * Loads the value of a given key. If distributed map doesn't contain the value\n     * for the given key then Hazelcast will call implementation's load (key) method\n     * to obtain the value. Implementation can use any means of loading the given key;\n     * such as an O/R mapping tool, simple SQL or reading a file etc.\n     *\n     * @param key@return value of the key, value cannot be null\n     */\n    @Override\n    public MessageBundle load(Long key) {\n        return getDatabaseStore().getMessage(key);\n    }\n\n    /**\n     * Loads given keys. This is batch load operation so that implementation can\n     * optimize the multiple loads.\n     * <p>\n     * For any key in the input keys, there should be a single mapping in the resulting map. Also the resulting\n     * map should not have any keys that are not part of the input keys.\n     * <p>\n     * The given collection should not contain any <code>null</code> keys.\n     * The returned Map should not contain any <code>null</code> keys or values.\n     *\n     * @param keys keys of the values entries to load\n     * @return map of loaded key-value pairs.\n     */\n    @Override\n    public Map<Long, MessageBundle> loadAll(Collection<Long> keys) {\n        return getDatabaseStore().getMessages(keys);\n    }\n\n    /**\n     * Loads all of the keys from the store. The returned {@link Iterable} may return the keys lazily\n     * by loading them in batches. The {@link Iterator} of this {@link Iterable} may implement the\n     * {@link Closeable} interface in which case it will be closed once iteration is over.\n     * This is intended for releasing resources such as closing a JDBC result set.\n     * <p>\n     * The returned Iterable should not contain any <code>null</code> keys.\n     *\n     * @return all the keys. Keys inside the Iterable cannot be null.\n     */\n    @Override\n    public Iterable<Long> loadAllKeys() {\n        return null;\n    }\n\n    @Override\n    public void store(Long aLong, MessageBundle messageBundle) {\n        getDatabaseStore().persistMessage(messageBundle.getMessage(), false);\n    }\n\n    @Override\n    public void storeAll(Map<Long, MessageBundle> map) {\n\n    }\n\n    @Override\n    public void delete(Long aLong) {\n\n    }\n\n    @Override\n    public void deleteAll(Collection<Long> collection) {\n\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/RobotLoader.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.persistence;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.core.MapStore;\nimport io.moquette.server.Server;\n\nimport java.util.Collection;\nimport java.util.Map;\n\npublic class RobotLoader implements MapStore<String, WFCMessage.Robot> {\n    @Override\n    public void store(String s, WFCMessage.Robot robot) {\n        getDatabaseStore().updateRobot(robot);\n    }\n\n    @Override\n    public void storeAll(Map<String, WFCMessage.Robot> map) {\n\n    }\n\n    @Override\n    public void delete(String s) {\n        getDatabaseStore().deleteRobot(s);\n    }\n\n    @Override\n    public void deleteAll(Collection<String> collection) {\n\n    }\n\n    private DatabaseStore getDatabaseStore() {\n        return Server.getServer().getStore().messagesStore().getDatabaseStore();\n    }\n\n    @Override\n    public WFCMessage.Robot load(String key) {\n        return getDatabaseStore().getRobot(key);\n    }\n\n    @Override\n    public Map<String, WFCMessage.Robot> loadAll(Collection<String> keys) {\n        return null;\n    }\n\n    @Override\n    public Iterable<String> loadAllKeys() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/ServerAPIHelper.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.persistence;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport io.moquette.persistence.remote.*;\nimport io.moquette.server.Server;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport cn.wildfirechat.common.ErrorCode;\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicInteger;\n\npublic class ServerAPIHelper {\n    private static final Logger LOG = LoggerFactory.getLogger(ServerAPIHelper.class);\n    public static final String CHECK_USER_ONLINE_REQUEST = \"check_user_online\";\n    public static final String KICKOFF_USER_REQUEST = \"kickoff_user\";\n\n    private static Server server;\n    public static ConcurrentHashMap<Integer, RequestInfo> requestMap = new ConcurrentHashMap<>();\n    private static AtomicInteger aiRequestId = new AtomicInteger(1);\n    public static ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);\n\n    public static void init(Server s) {\n        server = s;\n    }\n\n    public interface Callback {\n        void onSuccess(byte[] response);\n        void onError(ErrorCode errorCode);\n        void onTimeout();\n        Executor getResponseExecutor();\n    }\n\n    public static void sendRequest(String fromUser, String clientId, String request, byte[] message, Callback callback, ProtoConstants.RequestSourceType requestSourceType) {\n        int requestId = 0;\n\n        if (callback != null) {\n            requestId = aiRequestId.incrementAndGet();\n            if (requestId == Integer.MAX_VALUE) {\n                if(!aiRequestId.compareAndSet(Integer.MAX_VALUE, 1)) {\n                    requestId = aiRequestId.incrementAndGet();\n                }\n            }\n            requestMap.put(requestId, new RequestInfo(fromUser, clientId, callback, message, requestId, request));\n        }\n\n        server.onApiMessage(fromUser, clientId, message, requestId, \"\", request, requestSourceType);\n    }\n\n    public static void sendResponse(int errorCode, byte[] message, String toUuid, int requestId) {\n        LOG.debug(\"send async reponse to {} with requestId {}\", toUuid, requestId);\n        if (requestId > 0) {\n            RequestInfo info = requestMap.remove(requestId);\n            LOG.debug(\"receive async reponse requestId {}, errorCode {}\", requestId, errorCode);\n            if(info != null) {\n                info.future.cancel(true);\n                if (info.callback != null) {\n                    info.callback.getResponseExecutor().execute(() -> {\n                        if (errorCode == 0 || errorCode == ErrorCode.ERROR_CODE_SUCCESS_GZIPED.getCode()) {\n                            info.callback.onSuccess(message);\n                        } else {\n                            info.callback.onError(ErrorCode.fromCode(errorCode));\n                        }\n                    });\n                } else {\n\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/UserClientEntry.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.persistence;\n\nimport java.io.Serializable;\n\npublic class UserClientEntry implements Serializable {\n    public UserClientEntry(String userId, String clientId) {\n        this.userId = userId;\n        this.clientId = clientId;\n    }\n\n    public String userId;\n    public String clientId;\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/UserLoader.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.persistence;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.hazelcast.core.MapLoader;\nimport com.hazelcast.core.MapStore;\nimport io.moquette.server.Server;\n\nimport java.util.Collection;\nimport java.util.Map;\n\npublic class UserLoader implements MapStore<String, WFCMessage.User> {\n    @Override\n    public void store(String s, WFCMessage.User user) {\n//        getDatabaseStore().updateUser(user);\n    }\n\n    @Override\n    public void storeAll(Map<String, WFCMessage.User> map) {\n\n    }\n\n    @Override\n    public void delete(String s) {\n        getDatabaseStore().deleteUser(s);\n    }\n\n    @Override\n    public void deleteAll(Collection<String> collection) {\n\n    }\n\n    private DatabaseStore getDatabaseStore() {\n        return Server.getServer().getStore().messagesStore().getDatabaseStore();\n    }\n\n    @Override\n    public WFCMessage.User load(String key) {\n        return getDatabaseStore().getPersistUser(key);\n    }\n\n    @Override\n    public Map<String, WFCMessage.User> loadAll(Collection<String> keys) {\n        return null;\n    }\n\n    @Override\n    public Iterable<String> loadAllKeys() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/UserStatusLoader.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.persistence;\n\nimport com.hazelcast.core.MapStore;\nimport io.moquette.server.Server;\n\nimport java.util.Collection;\nimport java.util.Map;\n\npublic class UserStatusLoader implements MapStore<String, Integer> {\n    @Override\n    public void store(String s, Integer status) {\n        getDatabaseStore().updateUserStatus(s, status);\n    }\n\n    @Override\n    public void storeAll(Map<String, Integer> map) {\n\n    }\n\n    @Override\n    public void delete(String s) {\n        getDatabaseStore().deleteUserStatus(s);\n    }\n\n    @Override\n    public void deleteAll(Collection<String> collection) {\n\n    }\n\n    private DatabaseStore getDatabaseStore() {\n        return Server.getServer().getStore().messagesStore().getDatabaseStore();\n    }\n\n    @Override\n    public Integer load(String key) {\n        return getDatabaseStore().getUserStatus(key);\n    }\n\n    @Override\n    public Map<String, Integer> loadAll(Collection<String> keys) {\n        return null;\n    }\n\n    @Override\n    public Iterable<String> loadAllKeys() {\n        return null;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/persistence/remote/RequestInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage io.moquette.persistence.remote;\n\nimport io.moquette.persistence.ServerAPIHelper;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\npublic class RequestInfo {\n    private static final Logger LOG = LoggerFactory.getLogger(RequestInfo.class);\n    public final ServerAPIHelper.Callback callback;\n    final byte[] message;\n    final int requestId;\n    final String fromUser;\n    final String request;\n    final String clientId;\n    public final ScheduledFuture future;\n\n    public RequestInfo(String fromUser, String clientId, ServerAPIHelper.Callback callback, byte[] message, int requestId, String request) {\n        this.callback = callback;\n        this.message = message;\n        this.requestId = requestId;\n        this.fromUser = fromUser;\n        this.clientId = clientId;\n        this.request = request;\n        this.future = ServerAPIHelper.scheduledExecutorService.schedule(() -> {\n            RequestInfo info = ServerAPIHelper.requestMap.remove(requestId);\n            if (info != null) {\n                LOG.error(\"Request timeout. fromUser {}, cliendId {}, requestId {}, request {}\", fromUser, clientId, requestId, request);\n                info.callback.getResponseExecutor().execute(() -> {\n                    info.callback.onTimeout();\n                });\n            }\n        }, 5, TimeUnit.SECONDS);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/ConnectionDescriptor.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server;\n\nimport java.util.NoSuchElementException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport io.moquette.server.netty.AutoFlushHandler;\nimport io.moquette.server.netty.NettyUtils;\nimport io.moquette.server.netty.metrics.BytesMetrics;\nimport io.moquette.server.netty.metrics.BytesMetricsHandler;\nimport io.moquette.server.netty.metrics.MessageMetrics;\nimport io.moquette.server.netty.metrics.MessageMetricsHandler;\nimport io.netty.channel.Channel;\n\n/**\n * Value object to maintain the information of single connection, like ClientID, Channel, and clean\n * session flag.\n */\npublic class ConnectionDescriptor {\n\n    private static final Logger LOG = LoggerFactory.getLogger(ConnectionDescriptor.class);\n\n    public enum ConnectionState {\n        // Connection states\n        DISCONNECTED,\n        SENDACK,\n        SESSION_CREATED,\n        MESSAGES_REPUBLISHED,\n        ESTABLISHED,\n        // Disconnection states\n        MESSAGES_DROPPED,\n        INTERCEPTORS_NOTIFIED;\n    }\n\n    public final String clientID;\n    private final Channel channel;\n    private final AtomicReference<ConnectionState> channelState = new AtomicReference<>(ConnectionState.DISCONNECTED);\n\n    public ConnectionDescriptor(String clientID, Channel session) {\n        this.clientID = clientID;\n        this.channel = session;\n    }\n\n    public void writeAndFlush(Object payload) {\n        this.channel.writeAndFlush(payload);\n    }\n\n    public void setupAutoFlusher(int flushIntervalMs) {\n        try {\n            this.channel.pipeline().addAfter(\n                    \"idleEventHandler\",\n                    \"autoFlusher\",\n                    new AutoFlushHandler(flushIntervalMs, TimeUnit.MILLISECONDS));\n        } catch (NoSuchElementException nseex) {\n            // the idleEventHandler is not present on the pipeline\n            this.channel.pipeline()\n                    .addFirst(\"autoFlusher\", new AutoFlushHandler(flushIntervalMs, TimeUnit.MILLISECONDS));\n        }\n    }\n\n    public boolean doesNotUseChannel(Channel channel) {\n        return !(this.channel.equals(channel));\n    }\n\n    public boolean close() {\n        LOG.info(\"Closing connection descriptor. MqttClientId = {}.\", clientID);\n        final boolean success = assignState(ConnectionState.INTERCEPTORS_NOTIFIED, ConnectionState.DISCONNECTED);\n        if (!success) {\n            return false;\n        }\n        this.channel.close();\n        return true;\n    }\n\n    public String getUsername() {\n        return NettyUtils.userName(this.channel);\n    }\n\n    public void abort() {\n        LOG.info(\"Closing connection descriptor. MqttClientId = {}.\", clientID);\n        // try {\n        // this.channel.disconnect().sync();\n        this.channel.close(); // .sync();\n        // } catch (InterruptedException e) {\n        // e.printStackTrace();\n        // }\n    }\n\n    public boolean assignState(ConnectionState expected, ConnectionState newState) {\n        LOG.debug(\n                \"Updating state of connection descriptor. MqttClientId = {}, expectedState = {}, newState = {}.\",\n                clientID,\n                expected,\n                newState);\n        boolean retval = channelState.compareAndSet(expected, newState);\n        if (!retval) {\n            LOG.error(\n                    \"Unable to update state of connection descriptor.\"\n                    + \" MqttclientId = {}, expectedState = {}, newState = {}.\",\n                    clientID,\n                    expected,\n                    newState);\n        }\n        return retval;\n    }\n\n    @Override\n    public String toString() {\n        return \"ConnectionDescriptor{\" + \"clientID=\" + clientID + \", state=\"\n                + channelState.get() + '}';\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o)\n            return true;\n        if (o == null || getClass() != o.getClass())\n            return false;\n\n        ConnectionDescriptor that = (ConnectionDescriptor) o;\n\n        if (clientID != null ? !clientID.equals(that.clientID) : that.clientID != null)\n            return false;\n        return !(channel != null ? !channel.equals(that.channel) : that.channel != null);\n    }\n\n    public BytesMetrics getBytesMetrics() {\n        return BytesMetricsHandler.getBytesMetrics(channel);\n    }\n\n    public MessageMetrics getMessageMetrics() {\n        return MessageMetricsHandler.getMessageMetrics(channel);\n    }\n\n    @Override\n    public int hashCode() {\n        int result = clientID != null ? clientID.hashCode() : 0;\n        result = 31 * result + (channel != null ? channel.hashCode() : 0);\n        return result;\n    }\n\n    public Channel getChannel() {\n        return channel;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/ConnectionDescriptorStore.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server;\n\nimport io.moquette.connections.IConnectionsManager;\nimport io.moquette.connections.MqttConnectionMetrics;\nimport io.moquette.connections.MqttSession;\nimport io.moquette.server.netty.metrics.BytesMetrics;\nimport io.moquette.server.netty.metrics.MessageMetrics;\nimport io.moquette.spi.ClientSession;\nimport io.moquette.spi.ISessionsStore;\nimport io.netty.handler.codec.mqtt.MqttMessage;\nimport io.netty.handler.codec.mqtt.MqttMessageType;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport cn.wildfirechat.common.ErrorCode;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\npublic class ConnectionDescriptorStore implements IConnectionsManager {\n\n    private static final Logger LOG = LoggerFactory.getLogger(ConnectionDescriptorStore.class);\n\n    private final ConcurrentMap<String, ConnectionDescriptor> connectionDescriptors;\n    private final ISessionsStore sessionsStore;\n\n    public ConnectionDescriptorStore(ISessionsStore sessionsStore) {\n        this.connectionDescriptors = new ConcurrentHashMap<>();\n        this.sessionsStore = sessionsStore;\n    }\n\n    public boolean sendMessage(MqttMessage message, Integer messageID, String clientID, ErrorCode errorCode) {\n        final MqttMessageType messageType = message.fixedHeader().messageType();\n        try {\n            if (messageID != null) {\n                LOG.info(\"Sending {} message CId=<{}>, messageId={}, errorCode={}\", messageType, clientID, messageID, errorCode);\n            } else {\n                LOG.debug(\"Sending {} message CId=<{}>\", messageType, clientID);\n            }\n\n            ConnectionDescriptor descriptor = connectionDescriptors.get(clientID);\n            if (descriptor == null) {\n                if (messageID != null) {\n                    LOG.error(\"Client has just disconnected. {} message could not be sent. CId=<{}>, messageId={}\",\n                        messageType, clientID, messageID);\n                } else {\n                    LOG.error(\"Client has just disconnected. {} could not be sent. CId=<{}>\", messageType, clientID);\n                }\n                /*\n                 * If the client has just disconnected, its connection descriptor will be null. We\n                 * don't have to make the broker crash: we'll just discard the PUBACK message.\n                 */\n                return false;\n            }\n            descriptor.writeAndFlush(message);\n            return true;\n        } catch (Throwable e) {\n            String errorMsg = \"Unable to send \" + messageType + \" message. CId=<\" + clientID + \">\";\n            if (messageID != null) {\n                errorMsg += \", messageId=\" + messageID;\n            }\n            LOG.error(errorMsg, e);\n            return false;\n        }\n    }\n\n    public ConnectionDescriptor addConnection(ConnectionDescriptor descriptor) {\n        return connectionDescriptors.putIfAbsent(descriptor.clientID, descriptor);\n    }\n\n    public boolean removeConnection(ConnectionDescriptor descriptor) {\n        return connectionDescriptors.remove(descriptor.clientID, descriptor);\n    }\n\n    public ConnectionDescriptor getConnection(String clientID) {\n        return connectionDescriptors.get(clientID);\n    }\n\n    @Override\n    public boolean isConnected(String clientID) {\n        return connectionDescriptors.containsKey(clientID);\n    }\n\n    @Override\n    public int getActiveConnectionsNo() {\n        return connectionDescriptors.size();\n    }\n\n    @Override\n    public Collection<String> getConnectedClientIds() {\n        return connectionDescriptors.keySet();\n    }\n\n    @Override\n    public boolean closeConnection(String clientID, boolean closeImmediately) {\n        ConnectionDescriptor descriptor = connectionDescriptors.get(clientID);\n        if (descriptor == null) {\n            LOG.error(\"Connection descriptor doesn't exist. MQTT connection cannot be closed. CId=<{}>, \" +\n                \"closeImmediately={}\", clientID, closeImmediately);\n            return false;\n        }\n        if (closeImmediately) {\n            descriptor.abort();\n            return true;\n        } else {\n            return descriptor.close();\n        }\n    }\n\n    @Override\n    public MqttSession getSessionStatus(String clientID) {\n        LOG.info(\"Retrieving status of session. CId=<{}>\", clientID);\n        ClientSession session = sessionsStore.sessionForClient(clientID);\n        if (session == null) {\n            LOG.error(\"MQTT client ID doesn't have an associated session. CId=<{}>\", clientID);\n            return null;\n        }\n        return buildMqttSession(session);\n    }\n\n    @Override\n    public Collection<MqttSession> getSessions() {\n        LOG.info(\"Retrieving status of all sessions.\");\n        Collection<MqttSession> result = new ArrayList<>();\n        for (ClientSession session : sessionsStore.getAllSessions()) {\n            result.add(buildMqttSession(session));\n        }\n        return result;\n    }\n\n    private MqttSession buildMqttSession(ClientSession session) {\n        MqttSession result = new MqttSession();\n\n        result.setCleanSession(true);\n        ConnectionDescriptor descriptor = this.getConnection(session.clientID);\n        if (descriptor != null) {\n            result.setConnectionEstablished(true);\n            BytesMetrics bytesMetrics = descriptor.getBytesMetrics();\n            MessageMetrics messageMetrics = descriptor.getMessageMetrics();\n            result.setConnectionMetrics(new MqttConnectionMetrics(bytesMetrics.readBytes(), bytesMetrics.wroteBytes(),\n                messageMetrics.messagesRead(), messageMetrics.messagesWrote()));\n        } else {\n            result.setConnectionEstablished(false);\n        }\n        result.setPendingPublishMessagesNo(session.getPendingPublishMessagesNo());\n        result.setSecondPhaseAckPendingMessages(session.getSecondPhaseAckPendingMessages());\n        result.setInflightMessages(session.getInflightMessagesNo());\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/Constants.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server;\n\n/**\n * Server constants keeper\n */\npublic final class Constants {\n\n    public static final String ATTR_CLIENTID = \"ClientID\";\n    public static final String CLEAN_SESSION = \"cleanSession\";\n    public static final String KEEP_ALIVE = \"keepAlive\";\n\n\n    public static int MAX_MESSAGE_QUEUE = 1024; // number of messages\n    public static int MAX_CHATROOM_MESSAGE_QUEUE = 256; // number of chatroom messages\n\n    private Constants() {\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/DefaultMoquetteSslContextCreator.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server;\n\nimport io.moquette.BrokerConstants;\nimport io.moquette.server.config.IConfig;\nimport io.moquette.spi.security.ISslContextCreator;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.TrustManager;\nimport javax.net.ssl.TrustManagerFactory;\nimport java.io.*;\nimport java.net.URL;\nimport java.security.*;\nimport java.security.cert.CertificateException;\n\n/**\n * Moquette server implementation to load SSL certificate from local filesystem path configured in\n * config file.\n */\npublic class DefaultMoquetteSslContextCreator implements ISslContextCreator {\n\n    private static final Logger LOG = LoggerFactory.getLogger(DefaultMoquetteSslContextCreator.class);\n\n    private IConfig props;\n\n    public DefaultMoquetteSslContextCreator(IConfig props) {\n        this.props = props;\n    }\n\n    @Override\n    public SSLContext initSSLContext() {\n        LOG.info(\"Checking SSL configuration properties...\");\n        final String jksPath = props.getProperty(BrokerConstants.JKS_PATH_PROPERTY_NAME);\n        LOG.info(\"Initializing SSL context. KeystorePath = {}.\", jksPath);\n        if (jksPath == null || jksPath.isEmpty()) {\n            // key_store_password or key_manager_password are empty\n            LOG.warn(\"The keystore path is null or empty. The SSL context won't be initialized.\");\n            return null;\n        }\n\n        // if we have the port also the jks then keyStorePassword and keyManagerPassword\n        // has to be defined\n        final String keyStorePassword = props.getProperty(BrokerConstants.KEY_STORE_PASSWORD_PROPERTY_NAME);\n        final String keyManagerPassword = props.getProperty(BrokerConstants.KEY_MANAGER_PASSWORD_PROPERTY_NAME);\n        if (keyStorePassword == null || keyStorePassword.isEmpty()) {\n            // key_store_password or key_manager_password are empty\n            LOG.warn(\"The keystore password is null or empty. The SSL context won't be initialized.\");\n            return null;\n        }\n        if (keyManagerPassword == null || keyManagerPassword.isEmpty()) {\n            // key_manager_password or key_manager_password are empty\n            LOG.warn(\"The key manager password is null or empty. The SSL context won't be initialized.\");\n            return null;\n        }\n\n        // if client authentification is enabled a trustmanager needs to be\n        // added to the ServerContext\n        String sNeedsClientAuth = props.getProperty(BrokerConstants.NEED_CLIENT_AUTH, \"false\");\n        boolean needsClientAuth = Boolean.valueOf(sNeedsClientAuth);\n\n        try {\n            LOG.info(\"Loading keystore. KeystorePath = {}.\", jksPath);\n            InputStream jksInputStream = jksDatastore(jksPath);\n            SSLContext serverContext = SSLContext.getInstance(\"TLS\");\n            final KeyStore ks = KeyStore.getInstance(\"JKS\");\n            ks.load(jksInputStream, keyStorePassword.toCharArray());\n            LOG.info(\"Initializing key manager...\");\n            final KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n            kmf.init(ks, keyManagerPassword.toCharArray());\n            TrustManager[] trustManagers = null;\n            if (needsClientAuth) {\n                LOG.warn(\n                        \"Client authentication is enabled. \"\n                        + \"The keystore will be used as a truststore. KeystorePath = {}.\",\n                        jksPath);\n                // use keystore as truststore, as server needs to trust certificates signed by the\n                // server certificates\n                TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\n                tmf.init(ks);\n                trustManagers = tmf.getTrustManagers();\n            }\n            // init sslContext\n            LOG.info(\"Initializing SSL context...\");\n            serverContext.init(kmf.getKeyManagers(), trustManagers, null);\n            LOG.info(\"The SSL context has been initialized successfully.\");\n\n            return serverContext;\n        } catch (NoSuchAlgorithmException | UnrecoverableKeyException | CertificateException | KeyStoreException\n                | KeyManagementException | IOException ex) {\n            LOG.error(\n                    \"Unable to initialize SSL context. Cause = {}, errorMessage = {}.\",\n                    ex.getCause(),\n                    ex.getMessage());\n            return null;\n        }\n    }\n\n    private InputStream jksDatastore(String jksPath) throws FileNotFoundException {\n        URL jksUrl = getClass().getClassLoader().getResource(jksPath);\n        if (jksUrl != null) {\n            LOG.info(\"Starting with jks at {}, jks normal {}\", jksUrl.toExternalForm(), jksUrl);\n            return getClass().getClassLoader().getResourceAsStream(jksPath);\n        }\n        LOG.warn(\"No keystore has been found in the bundled resources. Scanning filesystem...\");\n        File jksFile = new File(jksPath);\n        if (jksFile.exists()) {\n            LOG.info(\"Loading external keystore. Url = {}.\", jksFile.getAbsolutePath());\n            return new FileInputStream(jksFile);\n        }\n        LOG.warn(\"The keystore file does not exist. Url = {}.\", jksFile.getAbsolutePath());\n        return null;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/Server.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.push.PushServer;\nimport cn.wildfirechat.server.ThreadPoolExecutorWrapper;\nimport com.hazelcast.config.ClasspathXmlConfig;\nimport com.hazelcast.config.Config;\nimport com.hazelcast.config.FileSystemXmlConfig;\nimport com.hazelcast.core.*;\nimport com.xiaoleilu.loServer.LoServer;\nimport com.xiaoleilu.loServer.ServerSetting;\nimport com.xiaoleilu.loServer.action.Action;\nimport com.xiaoleilu.loServer.action.admin.AdminAction;\nimport io.moquette.BrokerConstants;\nimport io.moquette.persistence.*;\nimport io.moquette.connections.IConnectionsManager;\nimport io.moquette.interception.*;\nimport io.moquette.server.config.*;\nimport io.moquette.server.netty.NettyAcceptor;\nimport io.moquette.spi.IStore;\nimport io.moquette.spi.impl.ProtocolProcessor;\nimport io.moquette.spi.impl.ProtocolProcessorBootstrapper;\nimport io.moquette.spi.impl.security.AES;\nimport io.moquette.spi.security.IAuthenticator;\nimport io.moquette.spi.security.IAuthorizator;\nimport io.moquette.spi.security.ISslContextCreator;\nimport io.moquette.spi.security.Tokenor;\nimport io.netty.util.ResourceLeakDetector;\nimport io.netty.util.internal.StringUtil;\nimport win.liyufan.im.DBUtil;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.MessageShardingUtil;\nimport win.liyufan.im.Utility;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.concurrent.Executors;\n\nimport static io.moquette.BrokerConstants.*;\nimport static io.moquette.logging.LoggingUtils.getInterceptorIds;\n\n/**\n * Launch a configured version of the server.\n */\npublic class Server {\n    private final static String BANNER =\n        \"            _  _      _   __  _                    _             _   \\n\" +\n        \" __      __(_)| |  __| | / _|(_) _ __  ___    ___ | |__    __ _ | |_ \\n\" +\n        \" \\\\ \\\\ /\\\\ / /| || | / _` || |_ | || '__|/ _ \\\\  / __|| '_ \\\\  / _` || __|\\n\" +\n        \"  \\\\ V  V / | || || (_| ||  _|| || |  |  __/ | (__ | | | || (_| || |_ \\n\" +\n        \"   \\\\_/\\\\_/  |_||_| \\\\__,_||_|  |_||_|   \\\\___|  \\\\___||_| |_| \\\\__,_| \\\\__|\\n\";\n\n\n    private static final Logger LOG = LoggerFactory.getLogger(Server.class);\n\n    private static Server instance;\n\n    public static Server getServer() {\n        return instance;\n    }\n\n    private ServerAcceptor m_acceptor;\n    private long startTime;\n\n    private boolean m_shutdowning = false;\n\n    public volatile boolean m_initialized;\n\n    private ProtocolProcessor m_processor;\n\n    private HazelcastInstance hazelcastInstance;\n\n    private ProtocolProcessorBootstrapper m_processorBootstrapper;\n\n    private ThreadPoolExecutorWrapper dbScheduler;\n    private ThreadPoolExecutorWrapper imBusinessScheduler;\n    private ThreadPoolExecutorWrapper callbackScheduler;\n\n    private IConfig mConfig;\n\n    private IStore m_store;\n    static {\n        System.out.println(BANNER);\n    }\n\n    public Server() {\n        startTime = System.currentTimeMillis();\n    }\n\n    public static void start(String[] args) throws IOException {\n        instance = new Server();\n        final IConfig config = defaultConfig();\n\n        System.setProperty(\"hazelcast.logging.type\", \"none\" );\n        instance.mConfig = config;\n        ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);\n\n        instance.startServer(config);\n\n        int httpLocalPort = Integer.parseInt(config.getProperty(BrokerConstants.HTTP_LOCAL_PORT));\n        int httpAdminPort = Integer.parseInt(config.getProperty(BrokerConstants.HTTP_ADMIN_PORT));\n\n        AdminAction.setSecretKey(config.getProperty(HTTP_SERVER_SECRET_KEY));\n        AdminAction.setNoCheckTime(config.getProperty(HTTP_SERVER_API_NO_CHECK_TIME));\n\n        final LoServer httpServer = new LoServer(httpLocalPort, httpAdminPort, instance.m_processor.getMessagesStore(), instance.m_store.sessionsStore());\n        try {\n            httpServer.start();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        final PushServer pushServer = PushServer.getServer();\n        pushServer.init(config, instance.getStore().sessionsStore());\n\n        //Bind  a shutdown hook\n        Runtime.getRuntime().addShutdownHook(new Thread(instance::stopServer));\n        Runtime.getRuntime().addShutdownHook(new Thread(httpServer::shutdown));\n\n        System.out.println(\"Wildfire IM server start success.\");\n    }\n\n    /**\n     * Starts Moquette bringing the configuration from the file located at m_config/wildfirechat.conf\n     *\n     * @throws IOException\n     *             in case of any IO error.\n     */\n    public void startServer() throws IOException {\n        final IConfig config = defaultConfig();\n        startServer(config);\n    }\n\n    public static IConfig defaultConfig() {\n        File defaultConfigurationFile = defaultConfigFile();\n        LOG.info(\"Starting Moquette server. Configuration file path={}\", defaultConfigurationFile.getAbsolutePath());\n        IResourceLoader filesystemLoader = new FileResourceLoader(defaultConfigurationFile);\n        return new ResourceLoaderConfig(filesystemLoader);\n    }\n\n    private static File defaultConfigFile() {\n        String configPath = System.getProperty(\"wildfirechat.path\", null);\n        return new File(configPath, IConfig.DEFAULT_CONFIG);\n    }\n\n\n    /**\n     * Starts Moquette bringing the configuration from the given file\n     *\n     * @param configFile\n     *            text file that contains the configuration.\n     * @throws IOException\n     *             in case of any IO Error.\n     */\n    public void startServer(File configFile) throws IOException {\n        LOG.info(\"Starting Moquette server. Configuration file path={}\", configFile.getAbsolutePath());\n        IResourceLoader filesystemLoader = new FileResourceLoader(configFile);\n        final IConfig config = new ResourceLoaderConfig(filesystemLoader);\n        startServer(config);\n    }\n\n    /**\n     * Starts the server with the given properties.\n     *\n     *\n     * @param configProps\n     *            the properties map to use as configuration.\n     * @throws IOException\n     *             in case of any IO Error.\n     */\n    public void startServer(Properties configProps) throws IOException {\n        LOG.info(\"Starting Moquette server using properties object\");\n        final IConfig config = new MemoryConfig(configProps);\n        startServer(config);\n    }\n\n    /**\n     * Starts Moquette bringing the configuration files from the given Config implementation.\n     *\n     * @param config\n     *            the configuration to use to start the broker.\n     * @throws IOException\n     *             in case of any IO Error.\n     */\n    public void startServer(IConfig config) throws IOException {\n        LOG.info(\"Starting Moquette server using IConfig instance...\");\n        startServer(config, null);\n    }\n\n    /**\n     * Starts Moquette with config provided by an implementation of IConfig class and with the set\n     * of InterceptHandler.\n     *\n     * @param config\n     *            the configuration to use to start the broker.\n     * @param handlers\n     *            the handlers to install in the broker.\n     * @throws IOException\n     *             in case of any IO Error.\n     */\n    public void startServer(IConfig config, List<? extends InterceptHandler> handlers) throws IOException {\n        LOG.info(\"Starting moquette server using IConfig instance and intercept handlers\");\n        startServer(config, handlers, null, null, null);\n    }\n\n    public void startServer(IConfig config, List<? extends InterceptHandler> handlers, ISslContextCreator sslCtxCreator,\n            IAuthenticator authenticator, IAuthorizator authorizator) throws IOException {\n        if (handlers == null) {\n            handlers = Collections.emptyList();\n        }\n        DBUtil.init(config);\n\n        LOG.info(\"Starting Moquette Server. MQTT message interceptors={}\", getInterceptorIds(handlers));\n\n        int threadNum = Runtime.getRuntime().availableProcessors() * 2;\n        dbScheduler = new ThreadPoolExecutorWrapper(Executors.newScheduledThreadPool(threadNum), threadNum, \"db\");\n        imBusinessScheduler = new ThreadPoolExecutorWrapper(Executors.newScheduledThreadPool(threadNum), threadNum, \"business\");\n        callbackScheduler = new ThreadPoolExecutorWrapper(Executors.newScheduledThreadPool(1), 1, \"callback\");\n\n        final String handlerProp = System.getProperty(BrokerConstants.INTERCEPT_HANDLER_PROPERTY_NAME);\n        if (handlerProp != null) {\n            config.setProperty(BrokerConstants.INTERCEPT_HANDLER_PROPERTY_NAME, handlerProp);\n        }\n\n        initMediaServerConfig(config);\n\n        Action.init(config);\n        String monitorEventAddress = config.getProperty(MONITOR_Exception_Event_Address);\n        Utility.setMonitorEventAddress(monitorEventAddress);\n\n        final String persistencePath = config.getProperty(BrokerConstants.PERSISTENT_STORE_PROPERTY_NAME);\n        LOG.info(\"Configuring Using persistent store file, path={}\", persistencePath);\n        m_store = initStore(config, this);\n        m_processorBootstrapper = new ProtocolProcessorBootstrapper();\n\n        boolean configured = configureCluster(config);\n\n        m_store.initStore();\n        final ProtocolProcessor processor = m_processorBootstrapper.init(config, handlers, authenticator, authorizator,\n            this, m_store);\n        LOG.info(\"Initialized MQTT protocol processor\");\n        if (sslCtxCreator == null) {\n            LOG.warn(\"Using default SSL context creator\");\n            sslCtxCreator = new DefaultMoquetteSslContextCreator(config);\n        }\n\n        m_processor = processor;\n\n        LOG.info(\"Binding server to the configured ports\");\n        m_acceptor = new NettyAcceptor();\n        m_acceptor.initialize(processor, config, sslCtxCreator);\n\n\n        LOG.info(\"Moquette server has been initialized successfully\");\n        m_initialized = configured;\n    }\n\n    private IStore initStore(IConfig props, Server server) {\n        LOG.info(\"Initializing messages and sessions stores...\");\n        IStore store = instantiateConfiguredStore(props, server.getDbScheduler(), server);\n        if (store == null) {\n            throw new IllegalArgumentException(\"Can't start the persistence layer\");\n        }\n        return store;\n    }\n\n    private IStore instantiateConfiguredStore(IConfig props,\n                                              ThreadPoolExecutorWrapper scheduledExecutor, Server server) {\n        return new MemoryStorageService(props, scheduledExecutor, server);\n    }\n\n    public IStore getStore() {\n        return m_store;\n    }\n\n    private void initMediaServerConfig(IConfig config) {\n    \tMediaServerConfig.QINIU_ACCESS_KEY = config.getProperty(BrokerConstants.QINIU_ACCESS_KEY, MediaServerConfig.QINIU_ACCESS_KEY);\n    \tMediaServerConfig.QINIU_SECRET_KEY = config.getProperty(BrokerConstants.QINIU_SECRET_KEY, MediaServerConfig.QINIU_SECRET_KEY);\n    \tMediaServerConfig.QINIU_SERVER_URL = config.getProperty(BrokerConstants.QINIU_SERVER_URL, MediaServerConfig.QINIU_SERVER_URL);\n    \tif (MediaServerConfig.QINIU_SERVER_URL.contains(\"//\")) {\n            MediaServerConfig.QINIU_SERVER_URL = MediaServerConfig.QINIU_SERVER_URL.substring(MediaServerConfig.QINIU_SERVER_URL.indexOf(\"//\") + 2);\n        }\n\n        MediaServerConfig.QINIU_BUCKET_GENERAL_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_GENERAL_NAME);\n        MediaServerConfig.QINIU_BUCKET_GENERAL_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_GENERAL_DOMAIN);\n\n        MediaServerConfig.QINIU_BUCKET_IMAGE_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_IMAGE_NAME);\n        MediaServerConfig.QINIU_BUCKET_IMAGE_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_IMAGE_DOMAIN);\n\n        MediaServerConfig.QINIU_BUCKET_VOICE_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_VOICE_NAME);\n        MediaServerConfig.QINIU_BUCKET_VOICE_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_VOICE_DOMAIN);\n\n        MediaServerConfig.QINIU_BUCKET_VIDEO_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_VIDEO_NAME);\n        MediaServerConfig.QINIU_BUCKET_VIDEO_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_VIDEO_DOMAIN);\n\n        MediaServerConfig.QINIU_BUCKET_FILE_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_FILE_NAME);\n        MediaServerConfig.QINIU_BUCKET_FILE_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_FILE_DOMAIN);\n\n        MediaServerConfig.QINIU_BUCKET_STICKER_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_STICKER_NAME);\n        MediaServerConfig.QINIU_BUCKET_STICKER_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_STICKER_DOMAIN);\n\n        MediaServerConfig.QINIU_BUCKET_MOMENTS_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_MOMENTS_NAME);\n        MediaServerConfig.QINIU_BUCKET_MOMENTS_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_MOMENTS_DOMAIN);\n\n        MediaServerConfig.QINIU_BUCKET_PORTRAIT_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_PORTRAIT_NAME);\n        MediaServerConfig.QINIU_BUCKET_PORTRAIT_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_PORTRAIT_DOMAIN);\n\n        MediaServerConfig.QINIU_BUCKET_FAVORITE_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_FAVORITE_NAME);\n        MediaServerConfig.QINIU_BUCKET_FAVORITE_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_FAVORITE_DOMAIN);\n\n        MediaServerConfig.QINIU_BUCKET_CUSTOM1_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_CUSTOM1_NAME);\n        MediaServerConfig.QINIU_BUCKET_CUSTOM1_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_CUSTOM1_DOMAIN);\n\n        MediaServerConfig.QINIU_BUCKET_CUSTOM2_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_CUSTOM2_NAME);\n        MediaServerConfig.QINIU_BUCKET_CUSTOM2_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_CUSTOM2_DOMAIN);\n\n        MediaServerConfig.QINIU_BUCKET_CUSTOM3_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_CUSTOM3_NAME);\n        MediaServerConfig.QINIU_BUCKET_CUSTOM3_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_CUSTOM3_DOMAIN);\n\n        MediaServerConfig.QINIU_BUCKET_PAN_NAME = config.getProperty(BrokerConstants.QINIU_BUCKET_PAN_NAME);\n        MediaServerConfig.QINIU_BUCKET_PAN_DOMAIN = config.getProperty(BrokerConstants.QINIU_BUCKET_PAN_DOMAIN);\n\n    \tMediaServerConfig.SERVER_IP = getServerIp(config);\n\n        MediaServerConfig.HTTP_SERVER_PORT = Integer.parseInt(config.getProperty(BrokerConstants.HTTP_SERVER_PORT));\n\n        MediaServerConfig.FILE_STROAGE_ROOT = config.getProperty(BrokerConstants.FILE_STORAGE_ROOT, MediaServerConfig.FILE_STROAGE_ROOT);\n        File file = new File(MediaServerConfig.FILE_STROAGE_ROOT);\n        if (!file.exists()) {\n            file.mkdirs();\n        }\n        ServerSetting.setRoot(file);\n        MediaServerConfig.FILE_STROAGE_REMOTE_SERVER_URL = config.getProperty(FILE_STORAGE_REMOTE_SERVER_URL);\n\n        MediaServerConfig.USER_QINIU = Integer.parseInt(config.getProperty(BrokerConstants.USER_QINIU)) > 0;\n        if(MediaServerConfig.USER_QINIU) {\n            if(MediaServerConfig.QINIU_SERVER_URL.split(\":\").length == 2) {\n                String error = \"媒体存储服务只能填上Host，不能带端口\";\n                System.out.println(error);\n                LOG.error(error);\n            }\n        }\n    }\n    \n    private String getServerIp(IConfig config) {\n        String serverIp = config.getProperty(BrokerConstants.SERVER_IP_PROPERTY_NAME);\n        if (serverIp == null || serverIp.equals(\"0.0.0.0\")) {\n            if(Utility.getLocalAddress() != null) {\n                serverIp = Utility.getLocalAddress().getHostAddress();\n            } else {\n                serverIp = \"0.0.0.0\";\n            }\n        }\n        return serverIp;\n    }\n\n    private boolean configureCluster(IConfig config) throws FileNotFoundException {\n        LOG.info(\"Configuring embedded Hazelcast instance\");\n\n        serverIp = getServerIp(config);\n        String hzConfigPath = System.getProperty(\"hazelcast.configuration\", \"config/hazelcast.xml\");\n        if (hzConfigPath != null) {\n            boolean isHzConfigOnClasspath = this.getClass().getClassLoader().getResource(hzConfigPath) != null;\n            Config hzconfig = isHzConfigOnClasspath\n                    ? new ClasspathXmlConfig(hzConfigPath)\n                    : new FileSystemXmlConfig(hzConfigPath);\n            LOG.info(\"Starting Hazelcast instance. ConfigurationFile={}\", hzconfig);\n            hazelcastInstance = Hazelcast.newHazelcastInstance(hzconfig);\n        } else {\n            LOG.info(\"Starting Hazelcast instance with default configuration\");\n            hazelcastInstance = Hazelcast.newHazelcastInstance();\n        }\n\n        longPort = config.getProperty(BrokerConstants.PORT_PROPERTY_NAME);\n        shortPort = config.getProperty(BrokerConstants.HTTP_SERVER_PORT);\n        boolean aes256 = Boolean.parseBoolean(config.getProperty(ENCRYPT_AES256, \"false\"));\n\n        MessageShardingUtil.setNodeId(1);\n        Tokenor.setKey(config.getProperty(BrokerConstants.TOKEN_SECRET_KEY));\n\n        AES.useAes256(aes256);\n\n        String expirTimeStr = config.getProperty(TOKEN_EXPIRE_TIME);\n        if (!StringUtil.isNullOrEmpty(expirTimeStr)) {\n            try {\n                Tokenor.setExpiredTime(Long.parseLong(expirTimeStr));\n            } catch (NumberFormatException e) {\n                e.printStackTrace();\n            }\n        }\n        ServerAPIHelper.init(this);\n        return true;\n    }\n\n    private String serverIp;\n    private String longPort;\n    private String shortPort;\n\n    public String getServerIp() {\n        return serverIp;\n    }\n\n    public String getLongPort() {\n        return longPort;\n    }\n\n    public String getShortPort() {\n        return shortPort;\n    }\n\n    public HazelcastInstance getHazelcastInstance() {\n        return hazelcastInstance;\n    }\n\n    public void onApiMessage(String fromUser, String clientId, byte[] message, int messageId, String from, String request, ProtoConstants.RequestSourceType requestSourceType) {\n        LOG.debug(\"onApiMessage\");\n        m_processor.onApiMessage(fromUser, clientId, message, messageId, from, request, requestSourceType);\n    }\n\n    public boolean isShutdowning() {\n        return m_shutdowning;\n    }\n\n    public void stopServer() {\n        System.out.println(\"Server will flush data to db before shutting down, please wait 5 seconds!\");\n        LOG.info(\"Unbinding server from the configured ports\");\n        m_shutdowning = true;\n        DBUtil.SystemExiting = true;\n\n        m_acceptor.close();\n        LOG.trace(\"Stopping MQTT protocol processor\");\n        m_processorBootstrapper.shutdown();\n        m_initialized = false;\n        if (hazelcastInstance != null) {\n            LOG.trace(\"Stopping embedded Hazelcast instance\");\n            try {\n                hazelcastInstance.shutdown();\n            } catch (HazelcastInstanceNotActiveException e) {\n                LOG.warn(\"embedded Hazelcast instance is already shut down.\");\n            }\n        }\n\n        dbScheduler.shutdown();\n        imBusinessScheduler.shutdown();\n        callbackScheduler.shutdown();\n\n        LOG.info(\"Moquette server has been stopped.\");\n    }\n\n    /**\n     * SPI method used by Broker embedded applications to add intercept handlers.\n     *\n     * @param interceptHandler\n     *            the handler to add.\n     */\n    public void addInterceptHandler(InterceptHandler interceptHandler) {\n        if (!m_initialized) {\n            LOG.error(\"Moquette is not started, MQTT message interceptor cannot be added. InterceptorId={}\",\n                interceptHandler.getID());\n            throw new IllegalStateException(\"Can't register interceptors on a server that is not yet started\");\n        }\n        LOG.info(\"Adding MQTT message interceptor. InterceptorId={}\", interceptHandler.getID());\n        m_processor.addInterceptHandler(interceptHandler);\n    }\n\n    /**\n     * SPI method used by Broker embedded applications to remove intercept handlers.\n     *\n     * @param interceptHandler\n     *            the handler to remove.\n     */\n    public void removeInterceptHandler(InterceptHandler interceptHandler) {\n        if (!m_initialized) {\n            LOG.error(\"Moquette is not started, MQTT message interceptor cannot be removed. InterceptorId={}\",\n                interceptHandler.getID());\n            throw new IllegalStateException(\"Can't deregister interceptors from a server that is not yet started\");\n        }\n        LOG.info(\"Removing MQTT message interceptor. InterceptorId={}\", interceptHandler.getID());\n        m_processor.removeInterceptHandler(interceptHandler);\n    }\n\n    public IConfig getConfig() {\n        return mConfig;\n    }\n\n    /**\n     * Returns the connections manager of this broker.\n     *\n     * @return IConnectionsManager the instance used bt the broker.\n     */\n    public IConnectionsManager getConnectionsManager() {\n        return m_processorBootstrapper.getConnectionDescriptors();\n    }\n\n    public ProtocolProcessor getProcessor() {\n        return m_processor;\n    }\n\n    public ThreadPoolExecutorWrapper getDbScheduler() {\n        return dbScheduler;\n    }\n\n    public ThreadPoolExecutorWrapper getImBusinessScheduler() {\n        return imBusinessScheduler;\n    }\n\n    public ThreadPoolExecutorWrapper getCallbackScheduler() {\n        return callbackScheduler;\n    }\n    public long getRunTime() {\n        return (System.currentTimeMillis() - startTime)/1000;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/ServerAcceptor.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server;\n\nimport java.io.IOException;\nimport io.moquette.server.config.IConfig;\nimport io.moquette.spi.impl.ProtocolProcessor;\nimport io.moquette.spi.security.ISslContextCreator;\n\npublic interface ServerAcceptor {\n\n    void initialize(ProtocolProcessor processor, IConfig props, ISslContextCreator sslCtxCreator) throws IOException;\n\n    void close();\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/config/ClasspathResourceLoader.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.config;\n\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.Reader;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class ClasspathResourceLoader implements IResourceLoader {\n\n    private static final Logger LOG = LoggerFactory.getLogger(ClasspathResourceLoader.class);\n\n    private final String defaultResource;\n    private final ClassLoader classLoader;\n\n    public ClasspathResourceLoader() {\n        this(IConfig.DEFAULT_CONFIG);\n    }\n\n    public ClasspathResourceLoader(String defaultResource) {\n        this(defaultResource, Thread.currentThread().getContextClassLoader());\n    }\n\n    public ClasspathResourceLoader(String defaultResource, ClassLoader classLoader) {\n        this.defaultResource = defaultResource;\n        this.classLoader = classLoader;\n    }\n\n    @Override\n    public Reader loadDefaultResource() {\n        return loadResource(defaultResource);\n    }\n\n    @Override\n    public Reader loadResource(String relativePath) {\n        LOG.info(\"Loading resource. RelativePath = {}.\", relativePath);\n        InputStream is = this.classLoader.getResourceAsStream(relativePath);\n        return is != null ? new InputStreamReader(is) : null;\n    }\n\n    @Override\n    public String getName() {\n        return \"classpath resource\";\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/config/ConfigurationParser.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.config;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.text.ParseException;\nimport java.util.Properties;\n\n/**\n * Mosquitto configuration parser.\n *\n * A line that at the very first has # is a comment Each line has key value format, where the\n * separator used it the space.\n */\nclass ConfigurationParser {\n\n    private static final Logger LOG = LoggerFactory.getLogger(ConfigurationParser.class);\n\n    private Properties m_properties = new Properties();\n\n    /**\n     * Parse the configuration from file.\n     */\n    void parse(File file) throws ParseException {\n        if (file == null) {\n            LOG.warn(\"parsing NULL file, so fallback on default configuration!\");\n            return;\n        }\n        if (!file.exists()) {\n            LOG.warn(\n                    String.format(\n                            \"parsing not existing file %s, so fallback on default configuration!\",\n                            file.getAbsolutePath()));\n            return;\n        }\n        try {\n            FileReader reader = new FileReader(file);\n            parse(reader);\n        } catch (FileNotFoundException fex) {\n            LOG.warn(\n                    String.format(\n                            \"parsing not existing file %s, so fallback on default configuration!\",\n                            file.getAbsolutePath()),\n                    fex);\n            return;\n        }\n    }\n\n    /**\n     * Parse the configuration\n     *\n     * @throws ParseException\n     *             if the format is not compliant.\n     */\n    void parse(Reader reader) throws ParseException {\n        if (reader == null) {\n            // just log and return default properties\n            LOG.warn(\"parsing NULL reader, so fallback on default configuration!\");\n            return;\n        }\n\n        BufferedReader br = new BufferedReader(reader);\n        String line;\n        try {\n            while ((line = br.readLine()) != null) {\n                line = line.trim();\n                int commentMarker = line.indexOf('#');\n                if (commentMarker != -1) {\n                    if (commentMarker == 0) {\n                        // skip its a comment\n                        continue;\n                    } else {\n                        String[] ss = line.split(\" \");\n                        if(ss.length != 2) {\n                            throw new ParseException(line, commentMarker);\n                        }\n                    }\n                } else {\n                    if (line.isEmpty() || line.matches(\"^\\\\s*$\")) {\n                        // skip it's a black line\n                        continue;\n                    }\n                }\n\n                // split till the first space\n                int delimiterIdx = line.indexOf(' ');\n                String key;\n                String value = \"\";\n                if (delimiterIdx > 0) {\n                    key = line.substring(0, delimiterIdx).trim();\n                    value = line.substring(delimiterIdx).trim();\n                } else {\n                    key = line.trim();\n                }\n\n                m_properties.put(key, value);\n            }\n        } catch (IOException ex) {\n            throw new ParseException(\"Failed to read\", 1);\n        } finally {\n            try {\n                reader.close();\n            } catch (IOException e) {\n                // ignore\n            }\n        }\n    }\n\n    Properties getProperties() {\n        return m_properties;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/config/FileResourceLoader.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.config;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileReader;\nimport java.io.Reader;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class FileResourceLoader implements IResourceLoader {\n\n    private static final Logger LOG = LoggerFactory.getLogger(FileResourceLoader.class);\n\n    private final File defaultFile;\n    private final String parentPath;\n\n    public FileResourceLoader() {\n        this((File) null);\n    }\n\n    public FileResourceLoader(File defaultFile) {\n        this(defaultFile, System.getProperty(\"wildfirechat.path\", null));\n    }\n\n    public FileResourceLoader(String parentPath) {\n        this(null, parentPath);\n    }\n\n    public FileResourceLoader(File defaultFile, String parentPath) {\n        this.defaultFile = defaultFile;\n        this.parentPath = parentPath;\n    }\n\n    @Override\n    public Reader loadDefaultResource() {\n        if (defaultFile != null) {\n            return loadResource(defaultFile);\n        } else {\n            throw new IllegalArgumentException(\"Default file not set!\");\n        }\n    }\n\n    @Override\n    public Reader loadResource(String relativePath) {\n        return loadResource(new File(parentPath, relativePath));\n    }\n\n    public Reader loadResource(File f) {\n        LOG.info(\"Loading file. Path = {}.\", f.getAbsolutePath());\n        if (f.isDirectory()) {\n            LOG.error(\"The given file is a directory. Path = {}.\", f.getAbsolutePath());\n            throw new ResourceIsDirectoryException(\"File \\\"\" + f + \"\\\" is a directory!\");\n        }\n        try {\n            return new FileReader(f);\n        } catch (FileNotFoundException e) {\n            LOG.error(\"The file does not exist. Path = {}.\", f.getAbsolutePath());\n            return null;\n        }\n    }\n\n    @Override\n    public String getName() {\n        return \"file\";\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/config/IConfig.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.config;\n\nimport io.moquette.BrokerConstants;\n\n/**\n * Base interface for all configuration implementations (filesystem, memory or classpath)\n */\npublic abstract class IConfig {\n\n    public static final String DEFAULT_CONFIG = \"config/wildfirechat.conf\";\n    public static final String LICENSE_PATH = \"config/wildfirechat.license\";\n\n    public abstract void setProperty(String name, String value);\n\n    public abstract String getProperty(String name);\n\n    public abstract String getProperty(String name, String defaultValue);\n\n    void assignDefaults() {\n        setProperty(BrokerConstants.PORT_PROPERTY_NAME, Integer.toString(BrokerConstants.PORT));\n        setProperty(BrokerConstants.HOST_PROPERTY_NAME, BrokerConstants.HOST);\n        setProperty(BrokerConstants.AUTHORIZATOR_CLASS_NAME, \"\");\n    }\n\n    public abstract IResourceLoader getResourceLoader();\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/config/IResourceLoader.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.config;\n\nimport java.io.Reader;\n\npublic interface IResourceLoader {\n\n    Reader loadDefaultResource();\n\n    Reader loadResource(String relativePath);\n\n    String getName();\n\n    class ResourceIsDirectoryException extends RuntimeException {\n\n        private static final long serialVersionUID = -6969292229582764176L;\n\n        public ResourceIsDirectoryException(String message) {\n            super(message);\n        }\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/config/MediaServerConfig.java",
    "content": "package io.moquette.server.config;\n\npublic class MediaServerConfig {\n\tpublic static String QINIU_SERVER_URL = \"up.qbox.me\";\n\tpublic static String QINIU_ACCESS_KEY = \"tU3vdBK5BL5j4N7jI5N5uZgq_HQDo170w5C9Amnn\";\n\tpublic static String QINIU_SECRET_KEY = \"YfQIJdgp5YGhwEw14vGpaD2HJZsuJldWtqens7i5\";\n\n    public static String QINIU_BUCKET_GENERAL_NAME;\n    public static String QINIU_BUCKET_GENERAL_DOMAIN;\n    public static String QINIU_BUCKET_IMAGE_NAME;\n    public static String QINIU_BUCKET_IMAGE_DOMAIN;\n    public static String QINIU_BUCKET_VOICE_NAME;\n    public static String QINIU_BUCKET_VOICE_DOMAIN;\n    public static String QINIU_BUCKET_VIDEO_NAME;\n    public static String QINIU_BUCKET_VIDEO_DOMAIN;\n    public static String QINIU_BUCKET_FILE_NAME;\n    public static String QINIU_BUCKET_FILE_DOMAIN;\n    public static String QINIU_BUCKET_STICKER_NAME;\n    public static String QINIU_BUCKET_STICKER_DOMAIN;\n    public static String QINIU_BUCKET_MOMENTS_NAME;\n    public static String QINIU_BUCKET_MOMENTS_DOMAIN;\n    public static String QINIU_BUCKET_PORTRAIT_NAME;\n    public static String QINIU_BUCKET_PORTRAIT_DOMAIN;\n    public static String QINIU_BUCKET_FAVORITE_NAME;\n    public static String QINIU_BUCKET_FAVORITE_DOMAIN;\n    public static String QINIU_BUCKET_CUSTOM1_NAME;\n    public static String QINIU_BUCKET_CUSTOM1_DOMAIN;\n    public static String QINIU_BUCKET_CUSTOM2_NAME;\n    public static String QINIU_BUCKET_CUSTOM2_DOMAIN;\n    public static String QINIU_BUCKET_CUSTOM3_NAME;\n    public static String QINIU_BUCKET_CUSTOM3_DOMAIN;\n    public static String QINIU_BUCKET_PAN_NAME;\n    public static String QINIU_BUCKET_PAN_DOMAIN;\n\n\n    public static String SERVER_IP = \"localhost\";\n    public static int HTTP_SERVER_PORT = 8080;\n    public static String FILE_STROAGE_ROOT = \"fs\";\n    public static String FILE_STROAGE_REMOTE_SERVER_URL;\n    public static boolean USER_QINIU = false;\n\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/config/MemoryConfig.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.config;\n\nimport java.util.Map;\nimport java.util.Properties;\n\n/**\n * Configuration backed by memory.\n */\npublic class MemoryConfig extends IConfig {\n\n    private final Properties m_properties = new Properties();\n\n    public MemoryConfig(Properties properties) {\n        assignDefaults();\n        for (Map.Entry<Object, Object> entrySet : properties.entrySet()) {\n            m_properties.put(entrySet.getKey(), entrySet.getValue());\n        }\n    }\n\n    @Override\n    public void setProperty(String name, String value) {\n        m_properties.setProperty(name, value);\n    }\n\n    @Override\n    public String getProperty(String name) {\n        return m_properties.getProperty(name);\n    }\n\n    @Override\n    public String getProperty(String name, String defaultValue) {\n        return m_properties.getProperty(name, defaultValue);\n    }\n\n    @Override\n    public IResourceLoader getResourceLoader() {\n        return new FileResourceLoader();\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/config/ResourceLoaderConfig.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.config;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport java.io.Reader;\nimport java.text.ParseException;\nimport java.util.Properties;\n\n/**\n * Configuration that loads config stream from a {@link IResourceLoader} instance.\n */\npublic class ResourceLoaderConfig extends IConfig {\n\n    private static final Logger LOG = LoggerFactory.getLogger(ResourceLoaderConfig.class);\n\n    private final Properties m_properties;\n    private final IResourceLoader resourceLoader;\n\n    public ResourceLoaderConfig(IResourceLoader resourceLoader) {\n        this(resourceLoader, null);\n    }\n\n    public ResourceLoaderConfig(IResourceLoader resourceLoader, String configName) {\n        LOG.info(\"Loading configuration. ResourceLoader = {}, configName = {}.\", resourceLoader.getName(), configName);\n        this.resourceLoader = resourceLoader;\n\n        /*\n         * If we use a conditional operator, the loadResource() and the loadDefaultResource()\n         * methods will be always called. This makes the log traces confusing.\n         */\n\n        Reader configReader;\n        if (configName != null) {\n            configReader = resourceLoader.loadResource(configName);\n        } else {\n            configReader = resourceLoader.loadDefaultResource();\n        }\n\n        if (configReader == null) {\n            LOG.error(\n                    \"The resource loader returned no configuration reader. ResourceLoader = {}, configName = {}.\",\n                    resourceLoader.getName(),\n                    configName);\n            throw new IllegalArgumentException(\"Can't locate \" + resourceLoader.getName() + \" \\\"\" + configName + \"\\\"\");\n        }\n\n        LOG.info(\n                \"Parsing configuration properties. ResourceLoader = {}, configName = {}.\",\n                resourceLoader.getName(),\n                configName);\n        ConfigurationParser confParser = new ConfigurationParser();\n        m_properties = confParser.getProperties();\n        assignDefaults();\n        try {\n            confParser.parse(configReader);\n        } catch (ParseException pex) {\n            LOG.warn(\n                    \"Unable to parse configuration properties. Using default configuration. \"\n                    + \"ResourceLoader = {}, configName = {}, cause = {}, errorMessage = {}.\",\n                    resourceLoader.getName(),\n                    configName,\n                    pex.getCause(),\n                    pex.getMessage());\n        }\n    }\n\n    @Override\n    public void setProperty(String name, String value) {\n        m_properties.setProperty(name, value);\n    }\n\n    @Override\n    public String getProperty(String name) {\n        return m_properties.getProperty(name);\n    }\n\n    @Override\n    public String getProperty(String name, String defaultValue) {\n        return m_properties.getProperty(name, defaultValue);\n    }\n\n    @Override\n    public IResourceLoader getResourceLoader() {\n        return resourceLoader;\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/netty/AutoFlushHandler.java",
    "content": "/*\n * Copyright (c) 2012-2016 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.netty;\n\nimport io.netty.channel.ChannelDuplexHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.util.concurrent.EventExecutor;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport java.util.concurrent.ScheduledFuture;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * Auto-flush data on channel after a read timeout. It's inspired by IdleStateHandler but it's\n * specialized version, just flushing data after no read is done on the channel after a period. It's\n * used to avoid aggressively flushing from the ProtocolProcessor.\n */\npublic class AutoFlushHandler extends ChannelDuplexHandler {\n\n    private static final Logger LOG = LoggerFactory.getLogger(AutoFlushHandler.class);\n    private static final long MIN_TIMEOUT_NANOS = TimeUnit.MILLISECONDS.toNanos(1);\n\n    private final long writerIdleTimeNanos;\n    volatile ScheduledFuture<?> writerIdleTimeout;\n    volatile long lastWriteTime;\n    // private boolean firstWriterIdleEvent = true;\n\n    private volatile int state; // 0 - none, 1 - initialized, 2 - destroyed\n\n    public AutoFlushHandler(long writerIdleTime, TimeUnit unit) {\n        if (unit == null) {\n            throw new NullPointerException(\"unit\");\n        }\n        writerIdleTimeNanos = Math.max(unit.toNanos(writerIdleTime), MIN_TIMEOUT_NANOS);\n    }\n\n    @Override\n    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {\n        if (ctx.channel().isActive() && ctx.channel().isRegistered()) {\n            // channelActive() event has been fired already, which means this.channelActive() will\n            // not be invoked. We have to initialize here instead.\n            initialize(ctx);\n        } else {\n            // channelActive() event has not been fired yet. this.channelActive() will be invoked\n            // and initialization will occur there.\n        }\n    }\n\n    @Override\n    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {\n        destroy();\n    }\n\n    @Override\n    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {\n        // Initialize early if channel is active already.\n        if (ctx.channel().isActive()) {\n            initialize(ctx);\n        }\n        super.channelRegistered(ctx);\n    }\n\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\n        // This method will be invoked only if this handler was added\n        // before channelActive() event is fired. If a user adds this handler\n        // after the channelActive() event, initialize() will be called by beforeAdd().\n        initialize(ctx);\n        super.channelActive(ctx);\n    }\n\n    @Override\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\n        destroy();\n        super.channelInactive(ctx);\n    }\n\n    // @Override\n    // public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n    // if (writerrIdleTimeNanos > 0) {\n    // reading = true;\n    // firstReaderIdleEvent = true;\n    // }\n    // ctx.fireChannelRead(msg);\n    // }\n    //\n    // @Override\n    // public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {\n    // if (writerrIdleTimeNanos > 0) {\n    // lastReadTime = System.nanoTime();\n    // reading = false;\n    // }\n    // ctx.fireChannelReadComplete();\n    // }\n\n    private void initialize(ChannelHandlerContext ctx) {\n        // Avoid the case where destroy() is called before scheduling timeouts.\n        // See: https://github.com/netty/netty/issues/143\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Initializing autoflush handler. MqttClientId = {}.\", NettyUtils.clientID(ctx.channel()));\n        }\n        switch (state) {\n            case 1:\n            case 2:\n                return;\n        }\n\n        state = 1;\n\n        EventExecutor loop = ctx.executor();\n\n        lastWriteTime = System.nanoTime();\n        writerIdleTimeout = loop.schedule(new WriterIdleTimeoutTask(ctx), writerIdleTimeNanos, TimeUnit.NANOSECONDS);\n    }\n\n    private void destroy() {\n        state = 2;\n\n        if (writerIdleTimeout != null) {\n            writerIdleTimeout.cancel(false);\n            writerIdleTimeout = null;\n        }\n    }\n\n    /**\n     * Is called when the write timeout expire.\n     *\n     * @param ctx\n     *            the channel context.\n     * @throws Exception\n     *             in case of any IO error.\n     */\n    protected void channelIdle(ChannelHandlerContext ctx/* , IdleStateEvent evt */) throws Exception {\n        // ctx.fireUserEventTriggered(evt);\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Flushing idle Netty channel. MqttClientId = {}.\", NettyUtils.clientID(ctx.channel()));\n        }\n        ctx.channel().flush();\n    }\n\n    private final class WriterIdleTimeoutTask implements Runnable {\n\n        private final ChannelHandlerContext ctx;\n\n        WriterIdleTimeoutTask(ChannelHandlerContext ctx) {\n            this.ctx = ctx;\n        }\n\n        @Override\n        public void run() {\n            if (!ctx.channel().isOpen()) {\n                return;\n            }\n\n            // long lastWriteTime = IdleStateHandler.this.lastWriteTime;\n            // long lastWriteTime = lastWriteTime;\n            long nextDelay = writerIdleTimeNanos - (System.nanoTime() - lastWriteTime);\n            if (nextDelay <= 0) {\n                // Writer is idle - set a new timeout and notify the callback.\n                writerIdleTimeout = ctx.executor().schedule(this, writerIdleTimeNanos, TimeUnit.NANOSECONDS);\n                try {\n                    /*\n                     * IdleStateEvent event; if (firstWriterIdleEvent) { firstWriterIdleEvent =\n                     * false; event = IdleStateEvent.FIRST_WRITER_IDLE_STATE_EVENT; } else { event =\n                     * IdleStateEvent.WRITER_IDLE_STATE_EVENT; }\n                     */\n                    channelIdle(ctx/* , event */);\n                } catch (Throwable t) {\n                    ctx.fireExceptionCaught(t);\n                }\n            } else {\n                // Write occurred before the timeout - set a new timeout with shorter delay.\n                writerIdleTimeout = ctx.executor().schedule(this, nextDelay, TimeUnit.NANOSECONDS);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/netty/MoquetteIdleTimeoutHandler.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.netty;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport io.netty.channel.ChannelDuplexHandler;\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.timeout.IdleState;\nimport io.netty.handler.timeout.IdleStateEvent;\n\n@Sharable\nclass MoquetteIdleTimeoutHandler extends ChannelDuplexHandler {\n\n    private static final Logger LOG = LoggerFactory.getLogger(MoquetteIdleTimeoutHandler.class);\n\n    @Override\n    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\n        if (evt instanceof IdleStateEvent) {\n            IdleState e = ((IdleStateEvent) evt).state();\n            if (e == IdleState.READER_IDLE) {\n                LOG.info(\"Firing channel inactive event. MqttClientId = {}.\", NettyUtils.clientID(ctx.channel()));\n                // fire a channelInactive to trigger publish of Will\n                ctx.fireChannelInactive();\n                ctx.close();\n            }\n        } else {\n            if (LOG.isDebugEnabled()) {\n                LOG.debug(\n                        \"Firing Netty event. MqttClientId = {}, eventClass = {}.\",\n                        NettyUtils.clientID(ctx.channel()),\n                        evt.getClass().getName());\n            }\n            super.userEventTriggered(ctx, evt);\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/netty/NettyAcceptor.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.netty;\n\nimport io.moquette.BrokerConstants;\nimport io.moquette.server.ServerAcceptor;\nimport io.moquette.server.config.IConfig;\nimport io.moquette.server.netty.metrics.*;\nimport io.moquette.spi.impl.ProtocolProcessor;\nimport io.moquette.spi.security.ISslContextCreator;\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.*;\nimport io.netty.channel.epoll.EpollEventLoopGroup;\nimport io.netty.channel.epoll.EpollServerSocketChannel;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.ServerSocketChannel;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.MessageToMessageDecoder;\nimport io.netty.handler.codec.MessageToMessageEncoder;\nimport io.netty.handler.codec.http.HttpObjectAggregator;\nimport io.netty.handler.codec.http.HttpRequestDecoder;\nimport io.netty.handler.codec.http.HttpResponseEncoder;\nimport io.netty.handler.codec.http.HttpServerCodec;\nimport io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;\nimport io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;\nimport io.netty.handler.codec.mqtt.MqttDecoder;\nimport io.netty.handler.codec.mqtt.MqttEncoder;\nimport io.netty.handler.ssl.SslHandler;\nimport io.netty.handler.timeout.IdleStateHandler;\nimport io.netty.util.concurrent.Future;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLEngine;\nimport java.io.IOException;\nimport java.net.BindException;\nimport java.util.List;\nimport java.util.Optional;\nimport java.util.concurrent.TimeUnit;\nimport static io.moquette.BrokerConstants.*;\nimport static io.netty.channel.ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE;\n\npublic class NettyAcceptor implements ServerAcceptor {\n\n    abstract class PipelineInitializer {\n\n        abstract void init(ChannelPipeline pipeline) throws Exception;\n    }\n\n    private static final Logger LOG = LoggerFactory.getLogger(NettyAcceptor.class);\n\n    EventLoopGroup m_bossGroup;\n    EventLoopGroup m_workerGroup;\n    BytesMetricsCollector m_bytesMetricsCollector = new BytesMetricsCollector();\n    MessageMetricsCollector m_metricsCollector = new MessageMetricsCollector();\n    private Optional<? extends ChannelInboundHandler> metrics;\n    private Optional<? extends ChannelInboundHandler> errorsCather;\n\n    private int nettySoBacklog;\n    private boolean nettySoReuseaddr;\n    private boolean nettyTcpNodelay;\n    private boolean nettySoKeepalive;\n    private int nettyChannelTimeoutSeconds;\n\n    private Class<? extends ServerSocketChannel> channelClass;\n\n    @Override\n    public void initialize(ProtocolProcessor processor, IConfig props, ISslContextCreator sslCtxCreator)\n            throws IOException {\n        LOG.info(\"Initializing Netty acceptor...\");\n\n        nettySoBacklog = Integer.parseInt(props.getProperty(BrokerConstants.NETTY_SO_BACKLOG_PROPERTY_NAME, \"128\"));\n        nettySoReuseaddr = Boolean\n                .parseBoolean(props.getProperty(BrokerConstants.NETTY_SO_REUSEADDR_PROPERTY_NAME, \"true\"));\n        nettyTcpNodelay = Boolean\n                .parseBoolean(props.getProperty(BrokerConstants.NETTY_TCP_NODELAY_PROPERTY_NAME, \"true\"));\n        nettySoKeepalive = Boolean\n                .parseBoolean(props.getProperty(BrokerConstants.NETTY_SO_KEEPALIVE_PROPERTY_NAME, \"true\"));\n        nettyChannelTimeoutSeconds = Integer\n                .parseInt(props.getProperty(BrokerConstants.NETTY_CHANNEL_TIMEOUT_SECONDS_PROPERTY_NAME, \"10\"));\n\n        boolean epoll = Boolean.parseBoolean(props.getProperty(BrokerConstants.NETTY_EPOLL_PROPERTY_NAME, \"false\"));\n        if (epoll) {\n            // 由于目前只支持TCP MQTT， 所以bossGroup的线程数配置为1\n            LOG.info(\"Netty is using Epoll\");\n            m_bossGroup = new EpollEventLoopGroup(1);\n            m_workerGroup = new EpollEventLoopGroup();\n            channelClass = EpollServerSocketChannel.class;\n        } else {\n            LOG.info(\"Netty is using NIO\");\n            m_bossGroup = new NioEventLoopGroup(1);\n            m_workerGroup = new NioEventLoopGroup();\n            channelClass = NioServerSocketChannel.class;\n        }\n\n        final NettyMQTTHandler mqttHandler = new NettyMQTTHandler(processor);\n\n        this.metrics = Optional.empty();\n\n        this.errorsCather = Optional.empty();\n\n        initializePlainTCPTransport(mqttHandler, props);\n    }\n\n    private void initFactory(String host, int port, String protocol, final PipelineInitializer pipeliner) {\n        LOG.info(\"Initializing server. Protocol={}\", protocol);\n        ServerBootstrap b = new ServerBootstrap();\n        b.group(m_bossGroup, m_workerGroup).channel(channelClass)\n                .childHandler(new ChannelInitializer<SocketChannel>() {\n\n                    @Override\n                    public void initChannel(SocketChannel ch) throws Exception {\n                        ChannelPipeline pipeline = ch.pipeline();\n                        try {\n                            pipeliner.init(pipeline);\n                        } catch (Throwable th) {\n                            LOG.error(\"Severe error during pipeline creation\", th);\n                            throw th;\n                        }\n                    }\n                })\n            .option(ChannelOption.SO_BACKLOG, nettySoBacklog)\n            .option(ChannelOption.SO_REUSEADDR, nettySoReuseaddr)\n            .childOption(ChannelOption.TCP_NODELAY, nettyTcpNodelay)\n            .childOption(ChannelOption.SO_KEEPALIVE, nettySoKeepalive);\n        try {\n            LOG.info(\"Binding server. host={}, port={}\", host, port);\n            // Bind and start to accept incoming connections.\n            ChannelFuture f = b.bind(host, port);\n            LOG.info(\"Server has been bound. host={}, port={}\", host, port);\n            f.sync().addListener(FIRE_EXCEPTION_ON_FAILURE);\n        } catch (InterruptedException ex) {\n            LOG.error(\"An interruptedException was caught while initializing server. Protocol={}\", protocol, ex);\n        } catch (Exception e) {\n            e.printStackTrace();\n            LOG.error(\"端口 {} 已经被占用或者无权限使用。如果无权限使用，请以root权限运行；如果被占用，请检查该端口被那个程序占用，找到程序停掉。\\n查找端口被那个程序占用的命令是: netstat -tunlp | grep {}\", port, port);\n            System.out.println(\"端口 \" + port + \" 已经被占用或者无权限使用。如果无权限使用，请以root权限运行；如果被占用，请检查该端口被那个程序占用，找到程序停掉。\\n查找端口被那个程序占用的命令是: netstat -tunlp | grep \" + port);\n            System.exit(-1);\n        }\n    }\n\n    private void initializePlainTCPTransport(final NettyMQTTHandler handler,\n                                             IConfig props) throws IOException {\n        LOG.info(\"Configuring TCP MQTT transport\");\n        final MoquetteIdleTimeoutHandler timeoutHandler = new MoquetteIdleTimeoutHandler();\n        String host = props.getProperty(BrokerConstants.HOST_PROPERTY_NAME, \"0.0.0.0\");\n        String tcpPortProp = props.getProperty(PORT_PROPERTY_NAME, DISABLED_PORT_BIND);\n        if (DISABLED_PORT_BIND.equals(tcpPortProp)) {\n            LOG.info(\"Property {} has been set to {}. TCP MQTT will be disabled\", BrokerConstants.PORT_PROPERTY_NAME,\n                DISABLED_PORT_BIND);\n            return;\n        }\n        int port = Integer.parseInt(tcpPortProp);\n        initFactory(host, port, \"TCP MQTT\", new PipelineInitializer() {\n\n            @Override\n            void init(ChannelPipeline pipeline) {\n                pipeline.addFirst(\"idleStateHandler\", new IdleStateHandler(nettyChannelTimeoutSeconds, 0, 0));\n                pipeline.addAfter(\"idleStateHandler\", \"idleEventHandler\", timeoutHandler);\n                // pipeline.addLast(\"logger\", new LoggingHandler(\"Netty\", LogLevel.ERROR));\n                if (errorsCather.isPresent()) {\n                    pipeline.addLast(\"bugsnagCatcher\", errorsCather.get());\n                }\n                pipeline.addFirst(\"bytemetrics\", new BytesMetricsHandler(m_bytesMetricsCollector));\n                pipeline.addLast(\"decoder\", new MqttDecoder());\n                pipeline.addLast(\"encoder\", MqttEncoder.INSTANCE);\n                pipeline.addLast(\"metrics\", new MessageMetricsHandler(m_metricsCollector));\n                pipeline.addLast(\"messageLogger\", new MQTTMessageLogger());\n                if (metrics.isPresent()) {\n                    pipeline.addLast(\"wizardMetrics\", metrics.get());\n                }\n                pipeline.addLast(\"handler\", handler);\n            }\n        });\n    }\n\n    public void close() {\n        LOG.info(\"Closing Netty acceptor...\");\n        if (m_workerGroup == null || m_bossGroup == null) {\n            LOG.error(\"Netty acceptor is not initialized\");\n            throw new IllegalStateException(\"Invoked close on an Acceptor that wasn't initialized\");\n        }\n        Future<?> workerWaiter = m_workerGroup.shutdownGracefully();\n        Future<?> bossWaiter = m_bossGroup.shutdownGracefully();\n\n        /*\n         * We shouldn't raise an IllegalStateException if we are interrupted. If we did so, the\n         * broker is not shut down properly.\n         */\n        LOG.info(\"Waiting for worker and boss event loop groups to terminate...\");\n        try {\n            workerWaiter.await(10, TimeUnit.SECONDS);\n            bossWaiter.await(10, TimeUnit.SECONDS);\n        } catch (InterruptedException iex) {\n            LOG.warn(\"An InterruptedException was caught while waiting for event loops to terminate...\");\n        }\n\n        if (!m_workerGroup.isTerminated()) {\n            LOG.warn(\"Forcing shutdown of worker event loop...\");\n            m_workerGroup.shutdownGracefully(0L, 0L, TimeUnit.MILLISECONDS);\n        }\n\n        if (!m_bossGroup.isTerminated()) {\n            LOG.warn(\"Forcing shutdown of boss event loop...\");\n            m_bossGroup.shutdownGracefully(0L, 0L, TimeUnit.MILLISECONDS);\n        }\n\n        LOG.info(\"Collecting message metrics...\");\n        MessageMetrics metrics = m_metricsCollector.computeMetrics();\n        LOG.info(\"Metrics have been collected. Read messages={}, written messages={}\", metrics.messagesRead(),\n            metrics.messagesWrote());\n\n        LOG.info(\"Collecting bytes metrics...\");\n        BytesMetrics bytesMetrics = m_bytesMetricsCollector.computeMetrics();\n        LOG.info(\"Bytes metrics have been collected. Read bytes={}, written bytes={}\", bytesMetrics.readBytes(),\n            bytesMetrics.wroteBytes());\n    }\n\n    private ChannelHandler createSslHandler(SSLContext sslContext, boolean needsClientAuth) {\n        SSLEngine sslEngine = sslContext.createSSLEngine();\n        sslEngine.setUseClientMode(false);\n        if (needsClientAuth) {\n            sslEngine.setNeedClientAuth(true);\n        }\n        return new SslHandler(sslEngine);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/netty/NettyMQTTHandler.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.netty;\n\nimport io.moquette.spi.impl.ProtocolProcessor;\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelInboundHandlerAdapter;\nimport io.netty.handler.codec.mqtt.*;\nimport io.netty.util.ReferenceCountUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE;\n\n@Sharable\npublic class NettyMQTTHandler extends ChannelInboundHandlerAdapter {\n\n    private static final Logger LOG = LoggerFactory.getLogger(NettyMQTTHandler.class);\n    private final ProtocolProcessor m_processor;\n\n    public NettyMQTTHandler(ProtocolProcessor processor) {\n        m_processor = processor;\n    }\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object message) {\n        try {\n            if (!(message instanceof MqttMessage)) {\n                LOG.error(\"Unknown mqtt message type {}, {}\", message.getClass().getName(), message);\n                return;\n            }\n            MqttMessage msg = (MqttMessage) message;\n            MqttMessageType messageType = msg.fixedHeader().messageType();\n            LOG.info(\"Processing MQTT message, type={}\", messageType);\n\n            switch (messageType) {\n                case CONNECT:\n                    m_processor.processConnect(ctx.channel(), (MqttConnectMessage) msg);\n                    break;\n                case SUBSCRIBE:\n                    m_processor.processSubscribe(ctx.channel(), (MqttSubscribeMessage) msg);\n                    break;\n                case UNSUBSCRIBE:\n                    m_processor.processUnsubscribe(ctx.channel(), (MqttUnsubscribeMessage) msg);\n                    break;\n                case PUBLISH:\n                    m_processor.processPublish(ctx.channel(), (MqttPublishMessage) msg);\n                    break;\n                case PUBREC:\n                    m_processor.processPubRec(ctx.channel(), msg);\n                    break;\n                case PUBCOMP:\n                    m_processor.processPubComp(ctx.channel(), msg);\n                    break;\n                case PUBREL:\n                    m_processor.processPubRel(ctx.channel(), msg);\n                    break;\n                case DISCONNECT:\n                    m_processor.processDisconnect(ctx.channel(), msg.fixedHeader().isDup(), msg.fixedHeader().isRetain());\n                    break;\n                case PUBACK:\n                    m_processor.processPubAck(ctx.channel(), (MqttPubAckMessage) msg);\n                    break;\n                case PINGREQ:\n                    MqttFixedHeader pingHeader = new MqttFixedHeader(\n                            MqttMessageType.PINGRESP,\n                            false,\n                            AT_MOST_ONCE,\n                            false,\n                            0);\n                    MqttMessage pingResp = new MqttMessage(pingHeader);\n                    ctx.writeAndFlush(pingResp);\n                    break;\n                default:\n                    LOG.error(\"Unkonwn MessageType:{}\", messageType);\n                    break;\n            }\n        } catch (Throwable ex) {\n            LOG.error(\"Exception was caught while processing MQTT message, \" + ex.getCause(), ex);\n            ctx.fireExceptionCaught(ex);\n            ctx.close();\n        } finally {\n            ReferenceCountUtil.release(message);\n        }\n    }\n\n    @Override\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\n        String clientID = NettyUtils.clientID(ctx.channel());\n        if (clientID != null && !clientID.isEmpty()) {\n            LOG.info(\"Notifying connection lost event. MqttClientId = {}.\", clientID);\n            m_processor.processConnectionLost(clientID, ctx.channel(), false);\n        }\n        ctx.close();\n    }\n\n    @Override\n    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {\n        LOG.error(\"An unexpected exception was caught while processing MQTT message. Closing Netty channel. CId={}, \" +\n            \"cause={}, errorMessage={}\", NettyUtils.clientID(ctx.channel()), cause.getCause(), cause.getMessage());\n        for (StackTraceElement ste : cause.getStackTrace()) {\n            LOG.error(ste.toString());\n        }\n        ctx.close();\n    }\n\n    @Override\n    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {\n        if (ctx.channel().isWritable()) {\n            m_processor.notifyChannelWritable(ctx.channel());\n        }\n        ctx.fireChannelWritabilityChanged();\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/netty/NettyUtils.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.netty;\n\nimport io.moquette.server.Constants;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.util.Attribute;\nimport io.netty.util.AttributeKey;\n\n/**\n * Some Netty's channels utilities.\n */\npublic final class NettyUtils {\n\n    public static final String ATTR_USERNAME = \"username\";\n    public static final String ATTR_SESSION_STOLEN = \"sessionStolen\";\n    public static final String ATTR_CHANNEL_STATUS = \"channelStatus\";\n\n    private static final AttributeKey<Object> ATTR_KEY_KEEPALIVE = AttributeKey.valueOf(Constants.KEEP_ALIVE);\n    private static final AttributeKey<Object> ATTR_KEY_CLEANSESSION = AttributeKey.valueOf(Constants.CLEAN_SESSION);\n    private static final AttributeKey<Object> ATTR_KEY_CLIENTID = AttributeKey.valueOf(Constants.ATTR_CLIENTID);\n    private static final AttributeKey<Object> ATTR_KEY_USERNAME = AttributeKey.valueOf(ATTR_USERNAME);\n\n    public static Object getAttribute(ChannelHandlerContext ctx, AttributeKey<Object> key) {\n        Attribute<Object> attr = ctx.channel().attr(key);\n        return attr.get();\n    }\n\n    public static void keepAlive(Channel channel, int keepAlive) {\n        channel.attr(NettyUtils.ATTR_KEY_KEEPALIVE).set(keepAlive);\n    }\n\n    public static void cleanSession(Channel channel, boolean cleanSession) {\n        channel.attr(NettyUtils.ATTR_KEY_CLEANSESSION).set(cleanSession);\n    }\n\n    public static boolean cleanSession(Channel channel) {\n        return (Boolean) channel.attr(NettyUtils.ATTR_KEY_CLEANSESSION).get();\n    }\n\n    public static void clientID(Channel channel, String clientID) {\n        channel.attr(NettyUtils.ATTR_KEY_CLIENTID).set(clientID);\n    }\n\n    public static String clientID(Channel channel) {\n        return (String) channel.attr(NettyUtils.ATTR_KEY_CLIENTID).get();\n    }\n\n    public static void userName(Channel channel, String username) {\n        channel.attr(NettyUtils.ATTR_KEY_USERNAME).set(username);\n    }\n\n    public static String userName(Channel channel) {\n        return (String) channel.attr(NettyUtils.ATTR_KEY_USERNAME).get();\n    }\n\n    private NettyUtils() {\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/netty/metrics/BytesMetrics.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.netty.metrics;\n\npublic class BytesMetrics {\n\n    private long m_readBytes;\n    private long m_wroteBytes;\n\n    void incrementRead(long numBytes) {\n        m_readBytes += numBytes;\n    }\n\n    void incrementWrote(long numBytes) {\n        m_wroteBytes += numBytes;\n    }\n\n    public long readBytes() {\n        return m_readBytes;\n    }\n\n    public long wroteBytes() {\n        return m_wroteBytes;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/netty/metrics/BytesMetricsCollector.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.netty.metrics;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Collects all the metrics from the various pipeline.\n */\npublic class BytesMetricsCollector {\n\n    private AtomicLong readBytes = new AtomicLong();\n    private AtomicLong wroteBytes = new AtomicLong();\n\n    public BytesMetrics computeMetrics() {\n        BytesMetrics allMetrics = new BytesMetrics();\n        allMetrics.incrementRead(readBytes.get());\n        allMetrics.incrementWrote(wroteBytes.get());\n        return allMetrics;\n    }\n\n    public void sumReadBytes(long count) {\n        readBytes.getAndAdd(count);\n    }\n\n    public void sumWroteBytes(long count) {\n        wroteBytes.getAndAdd(count);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/netty/metrics/BytesMetricsHandler.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.netty.metrics;\n\nimport io.moquette.server.netty.NettyUtils;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelDuplexHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelPromise;\nimport io.netty.util.Attribute;\nimport io.netty.util.AttributeKey;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static io.moquette.server.netty.NettyUtils.ATTR_USERNAME;\n\npublic class BytesMetricsHandler extends ChannelDuplexHandler {\n    private static final Logger LOG = LoggerFactory.getLogger(BytesMetricsHandler.class);\n    private static final AttributeKey<BytesMetrics> ATTR_KEY_METRICS = AttributeKey.valueOf(\"BytesMetrics\");\n    private static final AttributeKey<String> ATTR_KEY_USERNAME = AttributeKey.valueOf(ATTR_USERNAME);\n\n    private BytesMetricsCollector m_collector;\n\n    public BytesMetricsHandler(BytesMetricsCollector collector) {\n        m_collector = collector;\n    }\n\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\n        Attribute<BytesMetrics> attr = ctx.channel().attr(ATTR_KEY_METRICS);\n        attr.set(new BytesMetrics());\n\n        super.channelActive(ctx);\n    }\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n        BytesMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();\n        metrics.incrementRead(((ByteBuf) msg).readableBytes());\n        ctx.fireChannelRead(msg);\n    }\n\n    @Override\n    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {\n        BytesMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();\n        metrics.incrementWrote(((ByteBuf) msg).writableBytes());\n        ctx.write(msg, promise);\n    }\n\n    @Override\n    public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {\n        BytesMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();\n        String userId = ctx.channel().attr(ATTR_KEY_USERNAME).get();\n        if (userId == null) {\n            userId = \"\";\n        }\n\n        LOG.info(\"channel<{}> closing after read {} bytes and wrote {} bytes\", userId,  metrics.readBytes(), metrics.wroteBytes());\n        m_collector.sumReadBytes(metrics.readBytes());\n        m_collector.sumWroteBytes(metrics.wroteBytes());\n        super.close(ctx, promise);\n    }\n\n    public static BytesMetrics getBytesMetrics(Channel channel) {\n        return channel.attr(ATTR_KEY_METRICS).get();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/netty/metrics/MQTTMessageLogger.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.netty.metrics;\n\nimport io.moquette.server.netty.NettyUtils;\nimport io.netty.channel.ChannelDuplexHandler;\nimport io.netty.channel.ChannelHandler.Sharable;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelPromise;\nimport io.netty.handler.codec.mqtt.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.List;\n\nimport static io.moquette.spi.impl.Utils.messageId;\n\n/**\n *\n * @author andrea\n */\n@Sharable\npublic class MQTTMessageLogger extends ChannelDuplexHandler {\n\n    private static final Logger LOG = LoggerFactory.getLogger(\"messageLogger\");\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object message) {\n        logMQTTMessage(ctx, message, \"C->B\");\n        ctx.fireChannelRead(message);\n    }\n\n    private void logMQTTMessage(ChannelHandlerContext ctx, Object message, String direction) {\n        if (!(message instanceof MqttMessage)) {\n            return;\n        }\n        MqttMessage msg = (MqttMessage) message;\n        String clientID = NettyUtils.clientID(ctx.channel());\n        MqttMessageType messageType = msg.fixedHeader().messageType();\n        switch (messageType) {\n            case CONNECT:\n            case CONNACK:\n            case PINGREQ:\n            case PINGRESP:\n            case DISCONNECT:\n                LOG.info(\"{} {} <{}>\", direction, messageType, clientID);\n                break;\n            case SUBSCRIBE:\n                MqttSubscribeMessage subscribe = (MqttSubscribeMessage) msg;\n                LOG.info(\"{} SUBSCRIBE <{}> to topics {}\", direction, clientID,\n                    subscribe.payload().topicSubscriptions());\n                break;\n            case UNSUBSCRIBE:\n                MqttUnsubscribeMessage unsubscribe = (MqttUnsubscribeMessage) msg;\n                LOG.info(\"{} UNSUBSCRIBE <{}> to topics <{}>\", direction, clientID, unsubscribe.payload().topics());\n                break;\n            case PUBLISH:\n                MqttPublishMessage publish = (MqttPublishMessage) msg;\n                LOG.info(\"{} PUBLISH <{}> to topics <{}>\", direction, clientID, publish.variableHeader().topicName());\n                break;\n            case PUBREC:\n            case PUBCOMP:\n            case PUBREL:\n            case PUBACK:\n            case UNSUBACK:\n                LOG.info(\"{} {} <{}> packetID <{}>\", direction, messageType, clientID, messageId(msg));\n                break;\n            case SUBACK:\n                MqttSubAckMessage suback = (MqttSubAckMessage) msg;\n                final List<Integer> grantedQoSLevels = suback.payload().grantedQoSLevels();\n                LOG.info(\"{} SUBACK <{}> packetID <{}>, grantedQoses {}\", direction, clientID, messageId(msg),\n                    grantedQoSLevels);\n                break;\n        }\n    }\n\n    @Override\n    public void channelInactive(ChannelHandlerContext ctx) throws Exception {\n        String clientID = NettyUtils.clientID(ctx.channel());\n        if (clientID != null && !clientID.isEmpty()) {\n            LOG.info(\"Channel closed <{}>\", clientID);\n        }\n        ctx.fireChannelInactive();\n    }\n\n    @Override\n    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {\n        logMQTTMessage(ctx, msg, \"C<-B\");\n        ctx.write(msg, promise);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/netty/metrics/MessageMetrics.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.netty.metrics;\n\npublic class MessageMetrics {\n\n    private long m_messagesRead;\n    private long m_messageWrote;\n\n    void incrementRead(long numMessages) {\n        m_messagesRead += numMessages;\n    }\n\n    void incrementWrote(long numMessages) {\n        m_messageWrote += numMessages;\n    }\n\n    public long messagesRead() {\n        return m_messagesRead;\n    }\n\n    public long messagesWrote() {\n        return m_messageWrote;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/netty/metrics/MessageMetricsCollector.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.netty.metrics;\n\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * Collects all the metrics from the various pipeline.\n */\npublic class MessageMetricsCollector {\n\n    private AtomicLong readMsgs = new AtomicLong();\n    private AtomicLong wroteMsgs = new AtomicLong();\n\n    public MessageMetrics computeMetrics() {\n        MessageMetrics allMetrics = new MessageMetrics();\n        allMetrics.incrementRead(readMsgs.get());\n        allMetrics.incrementWrote(wroteMsgs.get());\n        return allMetrics;\n    }\n\n    public void sumReadMessages(long count) {\n        readMsgs.getAndAdd(count);\n    }\n\n    public void sumWroteMessages(long count) {\n        wroteMsgs.getAndAdd(count);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/server/netty/metrics/MessageMetricsHandler.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.server.netty.metrics;\n\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelDuplexHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.channel.ChannelPromise;\nimport io.netty.util.Attribute;\nimport io.netty.util.AttributeKey;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport static io.moquette.server.netty.NettyUtils.ATTR_USERNAME;\n\npublic class MessageMetricsHandler extends ChannelDuplexHandler {\n    private static final Logger LOG = LoggerFactory.getLogger(MessageMetricsHandler.class);\n    private static final AttributeKey<MessageMetrics> ATTR_KEY_METRICS = AttributeKey.valueOf(\"MessageMetrics\");\n    private static final AttributeKey<String> ATTR_KEY_USERNAME = AttributeKey.valueOf(ATTR_USERNAME);\n\n\n    private MessageMetricsCollector m_collector;\n\n    public MessageMetricsHandler(MessageMetricsCollector collector) {\n        m_collector = collector;\n    }\n\n    @Override\n    public void channelActive(ChannelHandlerContext ctx) throws Exception {\n        Attribute<MessageMetrics> attr = ctx.channel().attr(ATTR_KEY_METRICS);\n        attr.set(new MessageMetrics());\n\n        super.channelActive(ctx);\n    }\n\n    @Override\n    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n        MessageMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();\n        metrics.incrementRead(1);\n        ctx.fireChannelRead(msg);\n    }\n\n    @Override\n    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {\n        MessageMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();\n        metrics.incrementWrote(1);\n        ctx.write(msg, promise);\n    }\n\n    @Override\n    public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {\n        MessageMetrics metrics = ctx.channel().attr(ATTR_KEY_METRICS).get();\n        String userId = ctx.channel().attr(ATTR_KEY_USERNAME).get();\n        if (userId == null) {\n            userId = \"\";\n        }\n\n        LOG.info(\"channel<{}> closing after read {} messages and wrote {} messages\", userId,  metrics.messagesRead(), metrics.messagesWrote());\n        m_collector.sumReadMessages(metrics.messagesRead());\n        m_collector.sumWroteMessages(metrics.messagesWrote());\n        super.close(ctx, promise);\n    }\n\n    public static MessageMetrics getMessageMetrics(Channel channel) {\n        return channel.attr(ATTR_KEY_METRICS).get();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/ClientSession.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.HashSet;\nimport java.util.Queue;\nimport java.util.Set;\n\n/**\n * Model a Session like describe on page 25 of MQTT 3.1.1 specification:\n * The Session state in the Server consists of:\n * <ul>\n *     <li>The existence of a Session, even if the rest of the Session state is empty.</li>\n *     <li>The Client’s subscriptions.</li>\n *     <li>QoS 1 and QoS 2 messages which have been sent to the Client, but have not been\n *     completely acknowledged.</li>\n *     <li>QoS 1 and QoS 2 messages pending transmission to the Client.</li>\n *     <li>QoS 2 messages which have been received from the Client, but have not been\n *     completely acknowledged.</li>\n *     <li>Optionally, QoS 0 messages pending transmission to the Client.</li>\n * </ul>\n */\npublic class ClientSession {\n\n    class OutboundFlightZone {\n\n        /**\n         * Save the binding messageID, clientID - message\n         *\n         * @param messageID the packet ID used in transmission\n         * @param msg the message to put in flight zone\n         */\n        void waitingAck(int messageID, IMessagesStore.StoredMessage msg) {\n            if (LOG.isTraceEnabled()) {\n                LOG.trace(\"Adding to inflight {}, guid <{}>\", messageID, msg.getGuid());\n            }\n            m_sessionsStore.inFlight(ClientSession.this.clientID, messageID, msg);\n        }\n\n        IMessagesStore.StoredMessage acknowledged(int messageID) {\n            if (LOG.isTraceEnabled())\n                LOG.trace(\"Acknowledging inflight, clientID <{}> messageID {}\", ClientSession.this.clientID, messageID);\n            return m_sessionsStore.inFlightAck(ClientSession.this.clientID, messageID);\n        }\n    }\n\n    class InboundFlightZone {\n\n        public IMessagesStore.StoredMessage lookup(int messageID) {\n            return m_sessionsStore.inboundInflight(clientID, messageID);\n        }\n\n        public void waitingRel(int messageID, IMessagesStore.StoredMessage msg) {\n            m_sessionsStore.markAsInboundInflight(clientID, messageID, msg);\n        }\n    }\n\n    private static final Logger LOG = LoggerFactory.getLogger(ClientSession.class);\n\n    public final String clientID;\n\n    private final ISessionsStore m_sessionsStore;\n\n    // private BlockingQueue<AbstractMessage> m_queueToPublish = new\n    // ArrayBlockingQueue<>(Constants.MAX_MESSAGE_QUEUE);\n    private final OutboundFlightZone outboundFlightZone;\n    private final InboundFlightZone inboundFlightZone;\n\n    public ClientSession(String clientID, ISessionsStore sessionsStore) {\n        this.clientID = clientID;\n        this.m_sessionsStore = sessionsStore;\n        this.outboundFlightZone = new OutboundFlightZone();\n        this.inboundFlightZone = new InboundFlightZone();\n    }\n\n    /**\n     * Return the list of persisted publishes for the given clientID. For QoS1 and QoS2 with clean\n     * session flag, this method return the list of missed publish events while the client was\n     * disconnected.\n     *\n     * @return the list of messages to be delivered for client related to the session.\n     */\n    public Queue<IMessagesStore.StoredMessage> queue() {\n        LOG.info(\"Retrieving enqueued messages. CId={}\", clientID);\n        return this.m_sessionsStore.queue(clientID);\n    }\n\n    @Override\n    public String toString() {\n        return \"ClientSession{clientID='\" + clientID + '\\'' + \"}\";\n    }\n\n\n    public void disconnect(String userId, boolean cleanSession, boolean disableSession) {\n        if (cleanSession) {\n            LOG.info(\"Client disconnected. Removing its subscriptions. ClientId={}\", clientID);\n            // cleanup topic subscriptions\n            cleanSession(userId);\n        } else if(disableSession) {\n            LOG.info(\"Client disconnected. disable session. ClientId={}\", clientID);\n            m_sessionsStore.disableSession(userId, this.clientID);\n        }\n    }\n\n    public void cleanSession(String userId) {\n        m_sessionsStore.cleanSession(userId, this.clientID);\n    }\n\n\n    public int nextPacketId() {\n        return this.m_sessionsStore.nextPacketID(this.clientID);\n    }\n\n    public IMessagesStore.StoredMessage inFlightAcknowledged(int messageID) {\n        return outboundFlightZone.acknowledged(messageID);\n    }\n\n    /**\n     * Mark the message identified by guid as publish in flight.\n     *\n     * @return the packetID for the message in flight.\n     * */\n    public int inFlightAckWaiting(IMessagesStore.StoredMessage msg) {\n        LOG.debug(\"Adding message ot inflight zone. ClientId={}\", clientID);\n        int messageId = ClientSession.this.nextPacketId();\n        outboundFlightZone.waitingAck(messageId, msg);\n        return messageId;\n    }\n\n    public IMessagesStore.StoredMessage secondPhaseAcknowledged(int messageID) {\n        return m_sessionsStore.secondPhaseAcknowledged(clientID, messageID);\n    }\n\n    /**\n     * Enqueue a message to be sent to the client.\n     *\n     * @param message\n     *            the message to enqueue.\n     */\n    public void enqueue(IMessagesStore.StoredMessage message) {\n        this.m_sessionsStore.queue(this.clientID).add(message);\n    }\n\n    public IMessagesStore.StoredMessage inboundInflight(int messageID) {\n        return inboundFlightZone.lookup(messageID);\n    }\n\n    public void markAsInboundInflight(int messageID, IMessagesStore.StoredMessage msg) {\n        inboundFlightZone.waitingRel(messageID, msg);\n    }\n\n    public void moveInFlightToSecondPhaseAckWaiting(int messageID, IMessagesStore.StoredMessage msg) {\n        m_sessionsStore.moveInFlightToSecondPhaseAckWaiting(this.clientID, messageID, msg);\n    }\n\n    public int getPendingPublishMessagesNo() {\n        return m_sessionsStore.getPendingPublishMessagesNo(clientID);\n    }\n\n    public int getSecondPhaseAckPendingMessages() {\n        return m_sessionsStore.getSecondPhaseAckPendingMessages(clientID);\n    }\n\n    public int getInflightMessagesNo() {\n        return m_sessionsStore.getInflightMessagesNo(clientID);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/IMatchingCondition.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi;\n\nimport io.moquette.spi.impl.subscriptions.Topic;\n\npublic interface IMatchingCondition {\n\n    boolean match(Topic key);\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/IMessagesStore.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi;\n\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.xiaoleilu.loServer.model.FriendData;\nimport io.moquette.persistence.DatabaseStore;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.moquette.persistence.UserClientEntry;\nimport io.moquette.spi.impl.subscriptions.Topic;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.mqtt.MqttQoS;\nimport cn.wildfirechat.common.ErrorCode;\n\nimport java.util.*;\n\n/**\n * Defines the SPI to be implemented by a StorageService that handle persistence of messages\n */\npublic interface IMessagesStore {\n\n    class StoredMessage {\n\n        final MqttQoS m_qos;\n        final byte[] m_payload;\n        final String m_topic;\n        private boolean m_retained;\n        private String m_clientID;\n        private MessageGUID m_guid;\n\n        public StoredMessage(byte[] message, MqttQoS qos, String topic) {\n            m_qos = qos;\n            m_payload = message;\n            m_topic = topic;\n        }\n\n        public MqttQoS getQos() {\n            return m_qos;\n        }\n\n        public String getTopic() {\n            return m_topic;\n        }\n\n        public void setGuid(MessageGUID guid) {\n            this.m_guid = guid;\n        }\n\n        public MessageGUID getGuid() {\n            return m_guid;\n        }\n\n        public String getClientID() {\n            return m_clientID;\n        }\n\n        public void setClientID(String m_clientID) {\n            this.m_clientID = m_clientID;\n        }\n\n        public ByteBuf getPayload() {\n            return Unpooled.copiedBuffer(m_payload);\n        }\n\n        public void setRetained(boolean retained) {\n            this.m_retained = retained;\n        }\n\n        public boolean isRetained() {\n            return m_retained;\n        }\n\n        @Override\n        public String toString() {\n            return \"PublishEvent{clientID='\" + m_clientID + '\\'' + \", m_retain=\"\n                    + m_retained + \", m_qos=\" + m_qos + \", m_topic='\" + m_topic + '\\'' + '}';\n        }\n    }\n\n    DatabaseStore getDatabaseStore();\n    WFCMessage.Message storeMessage(String fromUser, String fromClientId, WFCMessage.Message message);\n    void storeSensitiveMessage(WFCMessage.Message message);\n\tint getNotifyReceivers(String fromUser, WFCMessage.Message.Builder message, Set<String> notifyReceivers, ProtoConstants.RequestSourceType requestSourceType);\n    Set<String> getAllEnds();\n    WFCMessage.PullMessageResult fetchMessage(String user, String exceptClientId, long fromMessageId, int pullType);\n    WFCMessage.PullMessageResult loadRemoteMessages(String user, WFCMessage.Conversation conversation, long beforeUid, int count, Collection<Integer> contentTypes);\n    long insertUserMessages(String sender, int conversationType, String target, int line, int messageContentType, String userId, long messageId, boolean directing);\n    ErrorCode canAddGroupMembers(String operator, List<WFCMessage.GroupMember> memberList, Map<String, Integer> failedMembers);\n    WFCMessage.GroupInfo createGroup(String operator, WFCMessage.GroupInfo groupInfo, List<WFCMessage.GroupMember> memberList, String memberExtra, boolean isAdmin, Map<String, Integer> failedMembers);\n    ErrorCode addGroupMembers(String operator, boolean isAdmin, String groupId, List<WFCMessage.GroupMember> memberList, String extra, Map<String, Integer> failedMembers);\n    ErrorCode kickoffGroupMembers(String operator, boolean isAdmin, String groupId, List<String> memberList);\n    ErrorCode quitGroup(String operator, String groupId, boolean admin);\n    void clearUserGroups(String userId);\n    ErrorCode dismissGroup(String operator, String groupId, boolean isAdmin);\n    ErrorCode modifyGroupInfo(String operator, String groupId, int modifyType, String value, boolean isAdmin);\n    ErrorCode modifyGroupMemberAlias(String operator, String groupId, String alias, String memberId, boolean isAdmin);\n    ErrorCode modifyGroupMemberExtra(String operator, String groupId, String extra, String memberId, boolean isAdmin);\n    List<WFCMessage.GroupInfo> getGroupInfos(List<WFCMessage.UserRequest> requests, String fromUser, boolean isAdmin);\n    WFCMessage.GroupInfo getGroupInfo(String groupId);\n    Set<String> getUserGroupIds(String userId);\n    Set<String> getUserGroupIds(String userId, List<Integer> types);\n    Set<String> getCommonGroupIds(String userId1, String userId2);\n    ErrorCode getGroupMembers(String fromUser, String groupId, long maxDt, List<WFCMessage.GroupMember> members);\n    WFCMessage.GroupMember getGroupMember(String groupId, String memberId);\n    ErrorCode transferGroup(String operator, String groupId, String newOwner, boolean isAdmin);\n    ErrorCode setGroupManager(String operator, String groupId, int type, List<String> userList, boolean isAdmin);\n    boolean isMemberInGroup(String member, String groupId);\n    ErrorCode canSendMessageInGroup(String member, String groupId);\n    Set<String> getGroupManagers(String groupId, boolean includeOwner);\n\n    ErrorCode recallMessage(long messageUid, String operatorId, String clientId, boolean isAdmin, ByteBuf ackPayload);\n    ErrorCode recallCastMessage(long messageUid, String operatorId);\n\n    void clearUserMessages(String userId);\n\n    WFCMessage.Robot getRobot(String robotId);\n    void addRobot(WFCMessage.Robot robot);\n    void destroyRobot(String robotId);\n\n    ErrorCode getUserInfo(String fromUser, List<WFCMessage.UserRequest> requestList, WFCMessage.PullUserResult.Builder builder);\n\n    ErrorCode modifyUserInfo(String userId, WFCMessage.ModifyMyInfoRequest request) throws Exception;\n\n    void forceCleanOnlineStatus(String userId, String clientId);\n\n    void updateUserOnlineSetting(MemorySessionStore.Session session, boolean online);\n\n    ErrorCode modifyUserStatus(String userId, int status);\n    int getUserStatus(String userId);\n    List<InputOutputUserBlockStatus> getUserStatusList();\n\n    ErrorCode updateUserInfo(InputOutputUserInfo userInfo, int flag);\n    void addUserInfo(WFCMessage.User user) throws Exception;\n    void destroyUser(String userId);\n    void updateUserInfo(WFCMessage.User user) throws Exception;\n    WFCMessage.User getUserInfo(String userId);\n    WFCMessage.User getUserInfoByName(String name);\n    WFCMessage.User getUserInfoByMobile(String mobile);\n    List<WFCMessage.User> getUserInfosByEmail(String email);\n    ErrorCode searchUser(String userId, String keyword, int searchType, int userType, int page, List<WFCMessage.User> users);\n\n    List<WFCMessage.User> getUserInfoList(int count, int offset);\n    List<String> getUserRobotIds(String userId);\n\n    boolean updateSystemSetting(int id, String value, String desc);\n    SystemSettingPojo getSystemSetting(int id);\n    void createChatroom(String chatroomId, WFCMessage.ChatroomInfo chatroomInfo);\n    void destoryChatroom(String chatroomId);\n    WFCMessage.ChatroomInfo getChatroomInfo(String chatroomId);\n    WFCMessage.ChatroomMemberInfo getChatroomMemberInfo(String chatroomId, final int maxMemberCount);\n    int getChatroomMemberCount(String chatroomId);\n    Collection<String> getChatroomMemberClient(String userId);\n    boolean checkUserClientInChatroom(String user, String clientId, String chatroomId);\n\n    long insertChatroomMessages(String target, int line, long messageId);\n    Collection<UserClientEntry> getChatroomMembers(String chatroomId);\n    OutputUserChatroom getUserChatroom(String userId);\n    WFCMessage.PullMessageResult fetchChatroomMessage(String fromUser, String chatroomId, String exceptClientId, long fromMessageId);\n\n    ErrorCode verifyToken(String userId, String token, List<String> serverIPs, List<Integer> ports);\n\n    List<FriendData> getFriendList(String userId, String clientId, long version);\n    void clearUserFriend(String userId);\n    List<WFCMessage.FriendRequest> getFriendRequestList(String userId, long version);\n\n    ErrorCode saveAddFriendRequest(String userId, WFCMessage.AddFriendRequest request, long[] head, boolean isAdmin, boolean isRobot);\n    ErrorCode handleFriendRequest(String userId, WFCMessage.HandleFriendRequest request, WFCMessage.Message.Builder msgBuilder, long[] heads, boolean isAdmin);\n    ErrorCode deleteFriend(String userId, String friendUid, long[] head);\n    ErrorCode blackUserRequest(String fromUser, String targetUserId, int status, long[] head);\n    FriendData getFriendData(String fromUser, String targetUserId);\n    ErrorCode SyncFriendRequestUnread(String userId, long unreadDt, long[] head);\n    ErrorCode isAllowUserMessage(String fromUser, String userId, int line);\n    ErrorCode isBlacked(String fromUser, String userId);\n    ErrorCode setFriendAliasRequest(String fromUser, String targetUserId, String alias, long[] head);\n    ErrorCode setFriendExtraRequest(String fromUser, String targetUserId, String extra, long[] head);\n\n    boolean isAllowName(String name);\n\n    ErrorCode handleJoinChatroom(String userId, String clientId, String chatroomId);\n    ErrorCode handleQuitChatroom(String userId, String clientId, String chatroomId);\n\n    boolean checkChatroomParticipantIdelTime(MemorySessionStore.Session session);\n\n\n    String getApplicationAuthCode(String fromUser, String applicationId, int appType, String host);\n    String verifyApplicationAuthCode(String token, String applicationId, int type);\n    ErrorCode configApplication(String appId, int appType, long timestamp, String nonce, String signature);\n\n    ErrorCode getUserSettings(String userId, long version, WFCMessage.GetUserSettingResult.Builder builder);\n    WFCMessage.UserSettingEntry getUserSetting(String userId, int scope, String key);\n    List<WFCMessage.UserSettingEntry> getUserSetting(String userId, int scope);\n    long updateUserSettings(String userId, WFCMessage.ModifyUserSettingReq request, String clientId);\n    void clearUserSettings(String userId);\n\n    boolean isLocked(String userId, String clientId);\n\n    boolean getUserGlobalSilent(String userId);\n    boolean getUserVoipSilent(String userId);\n\n    boolean getUserPushHiddenDetail(String userId);\n    boolean getUserConversationSilent(String userId, WFCMessage.Conversation conversation);\n    boolean getSilentWhenPcOnline(String userId);\n    boolean isUserNoDisturbing(String userId);\n    ErrorCode createChannel(String operator, WFCMessage.ChannelInfo channelInfo);\n    void clearUserChannels(String userId);\n    ErrorCode modifyChannelInfo(String operator, String channelId, int modifyType, String value);\n    ErrorCode transferChannel(String operator, String channelId, String newOwner);\n    ErrorCode destroyChannel(String operator, String channelId, boolean isAdmin);\n    List<WFCMessage.ChannelInfo> searchChannel(String keyword, boolean buzzy, int page);\n    List<String> getListenedChannels(String userId);\n    ErrorCode listenChannel(String operator, String channelId, boolean listen);\n    WFCMessage.ChannelInfo getChannelInfo(String channelId);\n    boolean canSendMessageInChannel(String user, String channelId);\n    boolean checkUserInChannel(String user, String channelId);\n    Collection<String> getChannelSubscriber(String channelId);\n\n    int getOnlineUserCount();\n    GetOnlineUserResult getOnlineUsers(int offset, int count);\n\n    Set<String> handleSensitiveWord(String message);\n    boolean addSensitiveWords(List<String> words);\n    boolean removeSensitiveWords(List<String> words);\n    List<String> getAllSensitiveWords();\n    boolean isSensitiveOnlyMessage();\n\n    WFCMessage.Message getMessage(long messageId);\n\n    void increaseUnreceivedMsgCount(String user);\n    int getUnreceivedMsgCount(String user);\n\n    boolean isAllowClientCustomGroupNotification();\n    boolean isAllowRobotCustomGroupNotification();\n    int getVisibleQuitKickoffNotification();\n\n    int getGroupForbiddenClientOperation();\n\n    boolean isForwardMessageWithClientInfo();\n    boolean isForwardMessageWithSenderInfo();\n    boolean isForwardMessageWithTargetInfo();\n\n    boolean isRobotCallbackWithClientInfo();\n    boolean isRobotCallbackWithSenderInfo();\n    boolean isRobotCallbackWithTargetInfo();\n    boolean isRobotMentionExternalRobot();\n    int getRobotGetUserInfoMask();\n\n    boolean isChannelCallbackWithClientInfo();\n    boolean isChannelCallbackWithSenderInfo();\n    boolean isChannelCallbackWithTargetInfo();\n    boolean isChannelNewCallbackFeature();\n    boolean isGroupAllowPartSuccess();\n    boolean isRobotAutoAcceptFriendRequest();\n\n    long getPushExpiredTimes();\n    Set<Integer> getForcePushTypes();\n\n    List<Integer> getClientForbiddenSendTypes();\n    List<Integer> getBlackListExceptionTypes();\n    List<Integer> getGroupMuteExceptionTypes();\n    List<Integer> getGlobalMuteExceptionTypes();\n\n    long getMessageHead(String user);\n    long getFriendHead(String user);\n    long getFriendRqHead(String user);\n    long getSettingHead(String user);\n\n    //使用了数据库，会比较慢，仅能用户用户/群组等id的生成\n    String getShortUUID();\n\n    boolean checkSignature(String signature);\n    boolean existSignatures();\n    /**\n     * Used to initialize all persistent store structures\n     */\n    void initStore();\n\n    /**\n     * Return a list of retained messages that satisfy the condition.\n     *\n     * @param condition\n     *            the condition to match during the search.\n     * @return the collection of matching messages.\n     */\n    Collection<StoredMessage> searchMatching(IMatchingCondition condition);\n\n    void cleanRetained(Topic topic);\n\n    void storeRetained(Topic topic, StoredMessage storedMessage);\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/IMessaging.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi;\n\n/**\n * Callback interface used to be notified of some events from the input event queue.\n *\n * It's the abstraction of the messaging stuff attached in after the front protocol parsing stuff.\n */\npublic interface IMessaging {\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/ISessionsStore.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.moquette.persistence.MemorySessionStore.Session;\nimport io.moquette.spi.IMessagesStore.StoredMessage;\nimport cn.wildfirechat.common.ErrorCode;\n\nimport java.util.Collection;\nimport java.util.Queue;\n\n/**\n * Store used to handle the persistence of the subscriptions tree.\n */\npublic interface ISessionsStore {\n\n    void initStore();\n\n    /**\n     * @param clientID\n     *            the session client ID.\n     * @return true iff there are subscriptions persisted with clientID\n     */\n    boolean contains(String clientID);\n\n    Session updateOrCreateUserSession(String username, String clientID, int platform);\n\n    ErrorCode loadActiveSession(String username, String clientID);\n\n    ClientSession updateExistSession(String username, String clientID, WFCMessage.RouteRequest endpoint, boolean cleanSession);\n    void updateSessionIp(String username, String clientID, String ip);\n    Session getSession(String clientID);\n\n    void cleanDuplatedToken(String cid, int pushType, String token, boolean isVoip, String packageName);\n\n    void updateSessionToken(Session session, boolean voip);\n\n    void clearUserSession(String username);\n\n    void kickoffUserClient(String userId, String clientId);\n    /**\n     * @param clientID\n     *            the client owning the session.\n     * @return the session for the given clientID, null if not found.\n     */\n\n    Session sessionForClientAndUser(String username, String clientID);\n\n    ClientSession sessionForClient(String clientID);\n\n    void loadUserSession(String username, String clientID);\n    \n    Collection<Session> sessionForUser(String username);\n\n    /**\n     * Returns all the sessions\n     *\n     * @return the collection of all stored client sessions.\n     */\n    Collection<ClientSession> getAllSessions();\n\n    boolean isClientOnline(String clientId);\n\n    StoredMessage inFlightAck(String clientID, int messageID);\n\n    /**\n     * Save the message msg with  messageID, clientID as in flight\n     *\n     * @param clientID\n     *            the client ID\n     * @param messageID\n     *            the message ID\n     * @param msg\n     *            the message to put in flight zone\n     */\n    void inFlight(String clientID, int messageID, StoredMessage msg);\n\n    /**\n     * Return the next valid packetIdentifier for the given client session.\n     *\n     * @param clientID\n     *            the clientID requesting next packet id.\n     * @return the next valid id.\n     */\n    int nextPacketID(String clientID);\n\n    /**\n     * List the published retained messages for the session\n     *\n     * @param clientID\n     *            the client ID owning the queue.\n     * @return the queue of messages.\n     */\n    Queue<StoredMessage> queue(String clientID);\n\n    void dropQueue(String clientID);\n\n    void moveInFlightToSecondPhaseAckWaiting(String clientID, int messageID, StoredMessage msg);\n\n    /**\n     * @param clientID\n     *            the client ID accessing the second phase.\n     * @param messageID\n     *            the message ID that reached the second phase.\n     * @return the guid of message just acked.\n     */\n    StoredMessage secondPhaseAcknowledged(String clientID, int messageID);\n\n    /**\n     * Returns the number of inflight messages for the given client ID\n     *\n     * @param clientID target client.\n     * @return count of pending in flight publish messages.\n     */\n    int getInflightMessagesNo(String clientID);\n\n    /**\n     * @return the inflight inbound (PUBREL for Qos2) message.\n     * */\n    IMessagesStore.StoredMessage inboundInflight(String clientID, int messageID);\n\n    void markAsInboundInflight(String clientID, int messageID, StoredMessage msg);\n\n    /**\n     * Returns the size of the session queue for the given client ID\n     *\n     * @param clientID target client.\n     * @return count of enqueued publish messages.\n     */\n    int getPendingPublishMessagesNo(String clientID);\n\n    /**\n     * Returns the number of second-phase ACK pending messages for the given client ID\n     *\n     * @param clientID target client.\n     * @return count of pending in flight publish messages.\n     */\n    int getSecondPhaseAckPendingMessages(String clientID);\n\n    void disableSession(String userId, String clientId);\n    void cleanSession(String userId, String clientID);\n\n    boolean isMultiEndpointSupported();\n\n    ErrorCode kickoffPCClient(String operator, String pcClientId);\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/IStore.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi;\n\npublic interface IStore {\n\n    void initStore();\n\n    void close();\n\n    /**\n     * Factory method to instantiate the messages store.\n     *\n     * @return the create instance of IMessagesStore.\n     * */\n    IMessagesStore messagesStore();\n\n    /**\n     * Factory method to instantiate the session store.\n     *\n     * @return the create instance of ISessionsStore.\n     * */\n    ISessionsStore sessionsStore();\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/MessageGUID.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi;\n\nimport java.io.Serializable;\n\n/**\n * Value object for GUIDs of messages.\n */\npublic class MessageGUID implements Serializable {\n\n    private static final long serialVersionUID = 4315161987111542406L;\n    private final String guid;\n\n    public MessageGUID(String guid) {\n        this.guid = guid;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o)\n            return true;\n        if (o == null || getClass() != o.getClass())\n            return false;\n\n        MessageGUID that = (MessageGUID) o;\n\n        return guid != null ? guid.equals(that.guid) : that.guid == null;\n    }\n\n    @Override\n    public int hashCode() {\n        return guid != null ? guid.hashCode() : 0;\n    }\n\n    @Override\n    public String toString() {\n        return \"MessageGUID{\" + \"guid='\" + guid + '\\'' + '}';\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/BrokerInterceptor.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl;\n\nimport io.moquette.BrokerConstants;\nimport io.moquette.interception.InterceptHandler;\nimport io.moquette.interception.Interceptor;\nimport io.moquette.interception.messages.*;\nimport io.moquette.server.config.IConfig;\nimport io.netty.handler.codec.mqtt.MqttConnectMessage;\nimport io.netty.handler.codec.mqtt.MqttPublishMessage;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport static io.moquette.logging.LoggingUtils.getInterceptorIds;\n\n/**\n * An interceptor that execute the interception tasks asynchronously.\n */\nfinal class BrokerInterceptor implements Interceptor {\n\n    private static final Logger LOG = LoggerFactory.getLogger(BrokerInterceptor.class);\n    private final Map<Class<?>, List<InterceptHandler>> handlers;\n    private final ExecutorService executor;\n\n    private BrokerInterceptor(int poolSize, List<InterceptHandler> handlers) {\n        LOG.info(\"Initializing broker interceptor. InterceptorIds={}\", getInterceptorIds(handlers));\n        this.handlers = new HashMap<>();\n        for (Class<?> messageType : InterceptHandler.ALL_MESSAGE_TYPES) {\n            this.handlers.put(messageType, new CopyOnWriteArrayList<InterceptHandler>());\n        }\n        for (InterceptHandler handler : handlers) {\n            this.addInterceptHandler(handler);\n        }\n        executor = Executors.newFixedThreadPool(poolSize);\n    }\n\n    /**\n     * Configures a broker interceptor, with a thread pool of one thread.\n     *\n     * @param handlers\n     */\n    BrokerInterceptor(List<InterceptHandler> handlers) {\n        this(1, handlers);\n    }\n\n    /**\n     * Configures a broker interceptor using the pool size specified in the IConfig argument.\n     */\n    BrokerInterceptor(IConfig props, List<InterceptHandler> handlers) {\n        this(Integer.parseInt(props.getProperty(BrokerConstants.BROKER_INTERCEPTOR_THREAD_POOL_SIZE, \"1\")), handlers);\n    }\n\n    /**\n     * Shutdown graciously the executor service\n     */\n    void stop() {\n        LOG.info(\"Shutting down interceptor thread pool...\");\n        executor.shutdown();\n        try {\n            LOG.info(\"Waiting for thread pool tasks to terminate...\");\n            executor.awaitTermination(10L, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n        }\n        if (!executor.isTerminated()) {\n            LOG.warn(\"Forcing shutdown of interceptor thread pool...\");\n            executor.shutdownNow();\n        }\n    }\n\n    @Override\n    public void notifyClientConnected(final MqttConnectMessage msg) {\n        for (final InterceptHandler handler : this.handlers.get(InterceptConnectMessage.class)) {\n            LOG.debug(\"Sending MQTT CONNECT message to interceptor. CId={}, interceptorId={}\",\n                    msg.payload().clientIdentifier(), handler.getID());\n            executor.execute(() -> handler.onConnect(new InterceptConnectMessage(msg)));\n        }\n    }\n\n    @Override\n    public void notifyClientDisconnected(final String clientID, final String username) {\n        for (final InterceptHandler handler : this.handlers.get(InterceptDisconnectMessage.class)) {\n            LOG.debug(\"Notifying MQTT client disconnection to interceptor. CId={}, username={}, interceptorId={}\",\n                clientID, username, handler.getID());\n            executor.execute(() -> handler.onDisconnect(new InterceptDisconnectMessage(clientID, username)));\n        }\n    }\n\n    @Override\n    public void notifyClientConnectionLost(final String clientID, final String username) {\n        for (final InterceptHandler handler : this.handlers.get(InterceptConnectionLostMessage.class)) {\n            LOG.debug(\"Notifying unexpected MQTT client disconnection to interceptor CId={}, username={}, \" +\n                \"interceptorId={}\", clientID, username, handler.getID());\n            executor.execute(() -> handler.onConnectionLost(new InterceptConnectionLostMessage(clientID, username)));\n        }\n    }\n\n    @Override\n    public void notifyMessageAcknowledged(final InterceptAcknowledgedMessage msg) {\n        for (final InterceptHandler handler : this.handlers.get(InterceptAcknowledgedMessage.class)) {\n            LOG.debug(\"Notifying MQTT ACK message to interceptor. CId={}, messageId={}, topic={}, interceptorId={}\",\n                msg.getMsg().getClientID(), msg.getPacketID(), msg.getTopic(), handler.getID());\n            executor.execute(() -> handler.onMessageAcknowledged(msg));\n        }\n    }\n\n    @Override\n    public void addInterceptHandler(InterceptHandler interceptHandler) {\n        Class<?>[] interceptedMessageTypes = getInterceptedMessageTypes(interceptHandler);\n        LOG.info(\"Adding MQTT message interceptor. InterceptorId={}, handledMessageTypes={}\",\n            interceptHandler.getID(), interceptedMessageTypes);\n        for (Class<?> interceptMessageType : interceptedMessageTypes) {\n            this.handlers.get(interceptMessageType).add(interceptHandler);\n        }\n    }\n\n    @Override\n    public void removeInterceptHandler(InterceptHandler interceptHandler) {\n        Class<?>[] interceptedMessageTypes = getInterceptedMessageTypes(interceptHandler);\n        LOG.info(\"Removing MQTT message interceptor. InterceptorId={}, handledMessageTypes={}\",\n            interceptHandler.getID(), interceptedMessageTypes);\n        for (Class<?> interceptMessageType : interceptedMessageTypes) {\n            this.handlers.get(interceptMessageType).remove(interceptHandler);\n        }\n    }\n\n    private static Class<?>[] getInterceptedMessageTypes(InterceptHandler interceptHandler) {\n        Class<?>[] interceptedMessageTypes = interceptHandler.getInterceptedMessageTypes();\n        if (interceptedMessageTypes == null) {\n            return InterceptHandler.ALL_MESSAGE_TYPES;\n        }\n        return interceptedMessageTypes;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/DebugUtils.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl;\n\nimport io.netty.buffer.ByteBuf;\n\nfinal class DebugUtils {\n\n    static String payload2Str(ByteBuf content) {\n        return new String(content.copy().array());\n    }\n\n    private DebugUtils() {\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/DesUtil.java",
    "content": "package io.moquette.spi.impl;\n\nimport java.io.IOException;\nimport java.security.SecureRandom;\nimport java.util.Base64;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.SecretKey;\nimport javax.crypto.SecretKeyFactory;\nimport javax.crypto.spec.DESKeySpec;\n\npublic class DesUtil {\n    private final static String Key = \"abcdefgh\";\n    private final static String DES = \"AES\";\n\n    public static void main(String[] args) throws Exception {\n        String data = \"123 456\";\n\n        System.err.println(encrypt(data));\n        System.err.println(decrypt(encrypt(data)));\n\n        System.out.println(decrypt(\"JF5dX/TlOg529KAhh+vywjzIp5Msktmf\"));\n\n    }\n\n    /**\n     * Description 根据键值进行加密\n     * @param data\n     * @return\n     * @throws Exception\n     */\n    public static String encrypt(String data) throws Exception {\n        byte[] bt = encrypt(data.getBytes(), Key.getBytes());\n        String strs = new String(Base64.getEncoder().encode(bt));\n        return strs;\n    }\n\n    /**\n     * Description 根据键值进行解密\n     * @param data\n     * @return\n     * @throws IOException\n     * @throws Exception\n     */\n    public static String decrypt(String data) throws IOException,\n        Exception {\n        if (data == null)\n            return null;\n\n        byte[] buf = Base64.getDecoder().decode(data);\n        byte[] bt = decrypt(buf,Key.getBytes());\n        return new String(bt);\n    }\n\n    /**\n     * Description 根据键值进行加密\n     * @param data\n     * @param key  加密键byte数组\n     * @return\n     * @throws Exception\n     */\n    private static byte[] encrypt(byte[] data, byte[] key) throws Exception {\n        // 生成一个可信任的随机数源\n        SecureRandom sr = new SecureRandom();\n\n        // 从原始密钥数据创建DESKeySpec对象\n        DESKeySpec dks = new DESKeySpec(key);\n\n        // 创建一个密钥工厂，然后用它把DESKeySpec转换成SecretKey对象\n        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);\n        SecretKey securekey = keyFactory.generateSecret(dks);\n\n        // Cipher对象实际完成加密操作\n        Cipher cipher = Cipher.getInstance(DES);\n\n        // 用密钥初始化Cipher对象\n        cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);\n\n        return cipher.doFinal(data);\n    }\n\n\n    /**\n     * Description 根据键值进行解密\n     * @param data\n     * @param key  加密键byte数组\n     * @return\n     * @throws Exception\n     */\n    private static byte[] decrypt(byte[] data, byte[] key) throws Exception {\n        // 生成一个可信任的随机数源\n        SecureRandom sr = new SecureRandom();\n\n        // 从原始密钥数据创建DESKeySpec对象\n        DESKeySpec dks = new DESKeySpec(key);\n\n        // 创建一个密钥工厂，然后用它把DESKeySpec转换成SecretKey对象\n        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);\n        SecretKey securekey = keyFactory.generateSecret(dks);\n\n        // Cipher对象实际完成解密操作\n        Cipher cipher = Cipher.getInstance(DES);\n\n        // 用密钥初始化Cipher对象\n        cipher.init(Cipher.DECRYPT_MODE, securekey, sr);\n\n        return cipher.doFinal(data);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/InternalRepublisher.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl;\n\nimport io.moquette.spi.ClientSession;\nimport io.moquette.spi.IMessagesStore;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.handler.codec.mqtt.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.Collection;\nimport java.util.Queue;\n\nclass InternalRepublisher {\n\n    private static final Logger LOG = LoggerFactory.getLogger(InternalRepublisher.class);\n\n    private final PersistentQueueMessageSender messageSender;\n\n    InternalRepublisher(PersistentQueueMessageSender messageSender) {\n        this.messageSender = messageSender;\n    }\n\n    void publishRetained(ClientSession targetSession, Collection<IMessagesStore.StoredMessage> messages) {\n        for (IMessagesStore.StoredMessage storedMsg : messages) {\n            // fire as retained the message\n            MqttPublishMessage publishMsg = retainedPublish(storedMsg);\n            if (storedMsg.getQos() != MqttQoS.AT_MOST_ONCE) {\n                LOG.debug(\"Adding message to inflight zone. ClientId={}, topic={}\", targetSession.clientID,\n                    storedMsg.getTopic());\n                int packetID = targetSession.inFlightAckWaiting(storedMsg);\n\n                // set the PacketIdentifier only for QoS > 0\n                publishMsg = retainedPublish(storedMsg, packetID);\n            }\n\n            this.messageSender.sendPublish(targetSession, publishMsg);\n        }\n    }\n\n    void publishStored(ClientSession clientSession, Queue<IMessagesStore.StoredMessage> publishedEvents) {\n        IMessagesStore.StoredMessage pubEvt;\n        while ((pubEvt = publishedEvents.poll()) != null) {\n            // put in flight zone\n            LOG.debug(\"Adding message ot inflight zone. ClientId={}, guid={}, topic={}\", clientSession.clientID,\n                pubEvt.getGuid(), pubEvt.getTopic());\n            int messageId = clientSession.inFlightAckWaiting(pubEvt);\n            MqttPublishMessage publishMsg = notRetainedPublish(pubEvt);\n            // set the PacketIdentifier only for QoS > 0\n            if (publishMsg.fixedHeader().qosLevel() != MqttQoS.AT_MOST_ONCE) {\n                publishMsg = notRetainedPublish(pubEvt, messageId);\n            }\n            this.messageSender.sendPublish(clientSession, publishMsg);\n        }\n    }\n\n    private MqttPublishMessage notRetainedPublish(IMessagesStore.StoredMessage storedMessage, Integer messageID) {\n        return createPublishForQos(storedMessage.getTopic(), storedMessage.getQos(), storedMessage.getPayload(), false,\n            messageID);\n    }\n\n    private MqttPublishMessage notRetainedPublish(IMessagesStore.StoredMessage storedMessage) {\n        return createPublishForQos(storedMessage.getTopic(), storedMessage.getQos(), storedMessage.getPayload(), false,\n            0);\n    }\n\n    private MqttPublishMessage retainedPublish(IMessagesStore.StoredMessage storedMessage) {\n        return createPublishForQos(storedMessage.getTopic(), storedMessage.getQos(), storedMessage.getPayload(), true,\n            0);\n    }\n\n    private MqttPublishMessage retainedPublish(IMessagesStore.StoredMessage storedMessage, Integer packetID) {\n        return createPublishForQos(storedMessage.getTopic(), storedMessage.getQos(), storedMessage.getPayload(), true,\n            packetID);\n    }\n\n    public static MqttPublishMessage createPublishForQos(String topic, MqttQoS qos, ByteBuf message, boolean retained,\n            int messageId) {\n        MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH, false, qos, retained, 0);\n        MqttPublishVariableHeader varHeader = new MqttPublishVariableHeader(topic, messageId);\n        return new MqttPublishMessage(fixedHeader, varHeader, message);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/MessagesPublisher.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl;\n\nimport org.json.simple.JSONObject;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.push.PushServer;\nimport com.hazelcast.core.HazelcastInstance;\nimport com.hazelcast.util.StringUtil;\nimport com.xiaoleilu.loServer.model.FriendData;\nimport io.moquette.persistence.*;\nimport io.moquette.persistence.MemorySessionStore.Session;\nimport io.moquette.server.ConnectionDescriptorStore;\nimport io.moquette.server.Server;\nimport io.moquette.spi.IMessagesStore;\nimport io.moquette.spi.ISessionsStore;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.handler.codec.mqtt.*;\nimport org.json.simple.parser.JSONParser;\nimport win.liyufan.im.*;\n\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.function.BiFunction;\n\nimport static cn.wildfirechat.common.IMExceptionEvent.EventType.EVENT_CALLBACK_Exception;\nimport static cn.wildfirechat.proto.ProtoConstants.ConversationType.*;\nimport static cn.wildfirechat.proto.ProtoConstants.PersistFlag.Transparent;\n\npublic class MessagesPublisher {\n    private static final Logger LOG = LoggerFactory.getLogger(MessagesPublisher.class);\n    private final ConnectionDescriptorStore connectionDescriptors;\n    private final ISessionsStore m_sessionsStore;\n    private final IMessagesStore m_messagesStore;\n    private final PersistentQueueMessageSender messageSender;\n    private ConcurrentHashMap<UserClientEntry, Long> chatRoomHeaders = new ConcurrentHashMap<>();\n    private ExecutorService chatroomScheduler = Executors.newFixedThreadPool(1);\n    private boolean schedulerStarted = false;\n    private static ExecutorService executorCallback = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());\n\n    public void startChatroomScheduler() {\n        schedulerStarted = true;\n        chatroomScheduler.execute(() -> {\n            while (schedulerStarted) {\n                try {\n                    if (chatRoomHeaders.size() < 100) {\n                        Thread.sleep(500);\n                    } else if(chatRoomHeaders.size() < 500) {\n                        Thread.sleep(100);\n                    }\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e);\n                }\n\n                chatRoomHeaders.forEach(100, (s, aLong) -> {\n                    chatRoomHeaders.remove(s, aLong);\n                    publish2ChatroomReceivers(s.userId, s.clientId, aLong);\n                });\n            }\n        });\n    }\n\n    public void stopChatroomScheduler() {\n        schedulerStarted = false;\n        try {\n            Thread.sleep(1000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n        chatroomScheduler.shutdown();\n    }\n\n    public MessagesPublisher(ConnectionDescriptorStore connectionDescriptors, ISessionsStore sessionsStore,\n                             PersistentQueueMessageSender messageSender, HazelcastInstance hz, IMessagesStore messagesStore) {\n        this.connectionDescriptors = connectionDescriptors;\n        this.m_sessionsStore = sessionsStore;\n        this.messageSender = messageSender;\n        this.m_messagesStore = messagesStore;\n        this.startChatroomScheduler();\n    }\n\n    static MqttPublishMessage notRetainedPublish(String topic, MqttQoS qos, ByteBuf message) {\n        return notRetainedPublishWithMessageId(topic, qos, message, 0);\n    }\n\n    private static MqttPublishMessage notRetainedPublishWithMessageId(String topic, MqttQoS qos, ByteBuf message,\n            int messageId) {\n        MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH, false, qos, false, 0);\n        MqttPublishVariableHeader varHeader = new MqttPublishVariableHeader(topic, messageId);\n        return new MqttPublishMessage(fixedHeader, varHeader, message);\n    }\n\n    private void publish2ChatroomReceivers(String user, String clientId, long messageHead) {\n        publish2ChatroomReceiversDirectly(user, clientId, messageHead);\n    }\n\n    public void publish2ChatroomReceiversDirectly(String user, String clientId, long messageHead) {\n        try {\n            Session session = m_sessionsStore.getSession(clientId);\n\n            if (session != null) {\n                LOG.warn(\"session for {} not exit\", clientId);\n                return;\n            }\n            if(!session.getUsername().equals(user)) {\n                LOG.warn(\"session {} user is not {}\", clientId, user);\n                return;\n            }\n            if (!this.connectionDescriptors.isConnected(clientId)) {\n                LOG.warn(\"session {} not connected\", clientId);\n                return;\n            }\n\n            WFCMessage.NotifyMessage notifyMessage = WFCMessage.NotifyMessage\n                .newBuilder()\n                .setType(ProtoConstants.PullType.Pull_ChatRoom)\n                .setHead(messageHead)\n                .build();\n\n            ByteBuf payload = Unpooled.buffer();\n            byte[] byteData = notifyMessage.toByteArray();\n            payload.ensureWritable(byteData.length).writeBytes(byteData);\n            MqttPublishMessage publishMsg;\n            publishMsg = notRetainedPublish(IMTopic.NotifyMessageTopic, MqttQoS.AT_MOST_ONCE, payload);\n\n            boolean result = !this.messageSender.sendPublish(session.getClientSession(), publishMsg);\n            if (!result) {\n                LOG.warn(\"send publish to {} failure\", clientId);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n    }\n\n    private void publish2Receivers(String sender, int conversationType, String target, int line, long messageId, Collection<String> receivers, String pushContent, String pushData, long callStartUid, String exceptClientId, int pullType, int messageContentType, long serverTime, int mentionType, List<String> mentionTargets, int persistFlag, boolean directing) {\n        if (persistFlag == Transparent) {\n            publishTransparentMessage2Receivers(messageId, receivers, pullType, exceptClientId);\n            return;\n        }\n\n        WFCMessage.Message message = null;\n        String senderName = null;\n        String senderPortrait = null;\n        boolean sendNameLoaded = false;\n        for (String user : receivers) {\n            if (!user.equals(sender)) {\n                WFCMessage.User userInfo = m_messagesStore.getUserInfo(user);\n                if (userInfo != null && userInfo.getType() == ProtoConstants.UserType.UserType_Robot) {\n                    WFCMessage.Robot robot = m_messagesStore.getRobot(user);\n                    if (robot != null && !StringUtil.isNullOrEmpty(robot.getCallback())) {\n                        if (message == null) {\n                            message = m_messagesStore.getMessage(messageId);\n                        }\n                        OutputMessageData outputMessageData = getOutputMessageWithExtraInfo(message, exceptClientId, m_messagesStore.isRobotCallbackWithClientInfo() , m_messagesStore.isRobotCallbackWithSenderInfo(), m_messagesStore.isRobotCallbackWithTargetInfo());\n                        outputMessageData.setToRobotId(robot.getUid());\n                        Server.getServer().getCallbackScheduler().execute(() -> {\n                            try {\n                                HttpUtils.httpJsonPost(robot.getCallback(), GsonUtil.gson.toJson(outputMessageData, OutputMessageData.class), HttpUtils.HttpPostType.POST_TYPE_Robot_Message_Callback);\n                            } catch (Exception e) {\n                                e.printStackTrace();\n                                Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n                            }\n                        });\n                        continue;\n                    }\n                }\n            }\n            long messageSeq;\n            if (pullType != ProtoConstants.PullType.Pull_ChatRoom) {\n                messageSeq = m_messagesStore.insertUserMessages(sender, conversationType, target, line, messageContentType, user, messageId, directing);\n            } else {\n                messageSeq = m_messagesStore.insertChatroomMessages(user, line, messageId);\n            }\n\n            Collection<Session> sessions = m_sessionsStore.sessionForUser(user);\n\n            String targetName = null;\n            String targetPortrait = null;\n            boolean targetNameLoaded = false;\n\n            Collection<String> targetClients = null;\n            if (pullType == ProtoConstants.PullType.Pull_ChatRoom) {\n                targetClients = m_messagesStore.getChatroomMemberClient(user);\n            }\n            boolean isPcOnline = false;\n\n            if (!user.equals(sender)) {\n                for (Session targetSession : sessions) {\n                    if (targetSession.getPlatform() == ProtoConstants.Platform.Platform_WEB\n                        || targetSession.getPlatform() == ProtoConstants.Platform.Platform_Windows\n                        || targetSession.getPlatform() == ProtoConstants.Platform.Platform_LINUX\n                        || targetSession.getPlatform() == ProtoConstants.Platform.Platform_OSX\n                        || targetSession.getPlatform() == ProtoConstants.Platform.Platform_HarmonyPC\n                        || targetSession.getPlatform() == ProtoConstants.Platform.Platform_iPad\n                        || targetSession.getPlatform() == ProtoConstants.Platform.Platform_APad\n                        || targetSession.getPlatform() == ProtoConstants.Platform.Platform_HarmonyPad\n                    ) {\n                        boolean targetIsActive = this.connectionDescriptors.isConnected(targetSession.getClientSession().clientID);\n                        if (targetIsActive) {\n                            isPcOnline = true;\n                            break;\n                        }\n                    }\n                }\n            }\n\n            boolean unreadCountIncreased = false;\n            for (Session targetSession : sessions) {\n                //超过7天不活跃的用户忽略\n                if(System.currentTimeMillis() - targetSession.getLastActiveTime() > m_messagesStore.getPushExpiredTimes()) {\n                    continue;\n                }\n\n                if (exceptClientId != null && exceptClientId.equals(targetSession.getClientSession().clientID)) {\n                    continue;\n                }\n\n                if (targetSession.getClientID() == null) {\n                    continue;\n                }\n\n                if (pullType == ProtoConstants.PullType.Pull_ChatRoom && !targetClients.contains(targetSession.getClientID())) {\n                    continue;\n                }\n\n                if (pullType == ProtoConstants.PullType.Pull_ChatRoom) {\n                    if (exceptClientId != null && exceptClientId.equals(targetSession.getClientID())) {\n                        targetSession.refreshLastChatroomActiveTime();\n                    }\n\n                    if (!m_messagesStore.checkChatroomParticipantIdelTime(targetSession)) {\n                        m_messagesStore.handleQuitChatroom(user, targetSession.getClientID(), target);\n                        continue;\n                    }\n                }\n\n                boolean isSilent;\n                boolean isVoipSilent;\n                boolean isNoDisturb;\n                boolean isConvSilent = false;\n                boolean isForcePush = false;\n                if (pullType == ProtoConstants.PullType.Pull_ChatRoom) {\n                    isSilent = true;\n                    isConvSilent = true;\n                    isVoipSilent = true;\n                    isNoDisturb = true;\n                } else {\n                    isSilent = false;\n                    isVoipSilent = false;\n                    isNoDisturb = false;\n\n                    if (!user.equals(sender)) {\n                        WFCMessage.Conversation conversation;\n                        if (conversationType == ConversationType_Private) {\n                            conversation = WFCMessage.Conversation.newBuilder().setType(conversationType).setLine(line).setTarget(sender).build();\n                        } else {\n                            conversation = WFCMessage.Conversation.newBuilder().setType(conversationType).setLine(line).setTarget(target).build();\n                        }\n\n                        if(m_messagesStore.getForcePushTypes().contains(messageContentType)) {\n                           LOG.info(\"The message type {} force push\", messageContentType);\n                            isForcePush = true;\n                        }\n\n                        if (m_messagesStore.getUserConversationSilent(user, conversation)) {\n                            LOG.info(\"The conversation {}-{}-{} is slient\", conversation.getType(), conversation.getTarget(), conversation.getLine());\n                            isConvSilent = true;\n                        }\n\n                        if (m_messagesStore.getUserGlobalSilent(user)) {\n                            LOG.info(\"The user {} is global sliented\", user);\n                            isSilent = true;\n                        }\n\n                        if (m_messagesStore.getUserVoipSilent(user)) {\n                            LOG.info(\"The user {} is voip sliented\", user);\n                            isVoipSilent = true;\n                        }\n\n                        if (!isSilent && isPcOnline && m_messagesStore.getSilentWhenPcOnline(user)) {\n                            LOG.info(\"The user {} pc online and silent when pc online\", user);\n                            isSilent = true;\n                        }\n\n                        if (m_messagesStore.isUserNoDisturbing(user)) {\n                            LOG.info(\"The user {} is no disturbing\", user);\n                            isNoDisturb = true;\n                        }\n                    }\n\n                    if (!StringUtil.isNullOrEmpty(pushContent) || messageContentType == 400) {\n                        if (!isConvSilent && (persistFlag & 0x02) > 0 && !unreadCountIncreased) {\n                            m_messagesStore.increaseUnreceivedMsgCount(user);\n                            unreadCountIncreased = true;\n                        }\n                    }\n                }\n\n                boolean needPush = !user.equals(sender);\n\n                boolean targetIsActive = this.connectionDescriptors.isConnected(targetSession.getClientSession().clientID);\n                if (targetIsActive) {\n                    WFCMessage.NotifyMessage notifyMessage = WFCMessage.NotifyMessage\n                        .newBuilder()\n                        .setType(pullType)\n                        .setHead(messageSeq)\n                        .build();\n\n                    ByteBuf payload = Unpooled.buffer();\n                    byte[] byteData = notifyMessage.toByteArray();\n                    payload.ensureWritable(byteData.length).writeBytes(byteData);\n                    MqttPublishMessage publishMsg;\n                    publishMsg = notRetainedPublish(IMTopic.NotifyMessageTopic, MqttQoS.AT_MOST_ONCE, payload);\n\n                    boolean sent = this.messageSender.sendPublish(targetSession.getClientSession(), publishMsg);\n                    if (sent) {\n                        needPush = false;\n                    }\n                } else {\n                    LOG.info(\"the target {} of user {} is not active\", targetSession.getClientID(), targetSession.getUsername());\n                }\n\n                if (needPush && pullType != ProtoConstants.PullType.Pull_ChatRoom) {\n                    int curMentionType = 0;\n                    if (mentionType == 2) {\n                        curMentionType = 2;\n                        isConvSilent = false;\n                    } else if (mentionType == 1){\n                        if (mentionTargets != null && mentionTargets.contains(user)) {\n                            curMentionType = 1;\n                            isConvSilent = false;\n                        }\n                    }\n                    boolean isVoip = messageContentType == 402 || messageContentType == 400 || messageContentType == 401 || messageContentType == 406;\n\n                    if (StringUtil.isNullOrEmpty(pushContent) && StringUtil.isNullOrEmpty(pushData) && !isVoip) {\n                        LOG.info(\"push content is empty and contenttype is {}\", messageContentType);\n                        continue;\n                    }\n\n                    if (StringUtil.isNullOrEmpty(targetSession.getDeviceToken())) {\n                        LOG.info(\"device token not exist\");\n                        continue;\n                    }\n\n                    if (isConvSilent && !isVoip && !isForcePush) {\n                        LOG.info(\"Silent of user or conversation\");\n                        continue;\n                    }\n\n                    if (isSilent && !isVoip && !isForcePush) {\n                        LOG.info(\"Silent of user\");\n                        continue;\n                    }\n\n                    if(isVoip && isVoipSilent && !isForcePush) {\n                        LOG.info(\"voip silent of user\");\n                        continue;\n                    }\n\n                    if(isNoDisturb) {\n                        LOG.info(\"no disturb of user\");\n                        continue;\n                    }\n\n                    boolean isHiddenDetail = m_messagesStore.getUserPushHiddenDetail(user);\n\n                    if(!sendNameLoaded) {\n                        List<String> list = new ArrayList<>();\n                        senderName = getUserDisplayName(sender, conversationType == ConversationType_Group ? target : null, list);\n                        if(!list.isEmpty()) {\n                            senderPortrait = list.get(0);\n                        }\n                        sendNameLoaded = true;\n                    }\n\n                    if(!targetNameLoaded) {\n                        List<String> list = new ArrayList<>();\n                        targetName = getTargetName(target, conversationType, user, list);\n                        if(!list.isEmpty()) {\n                            targetPortrait = list.get(0);\n                        }\n                        targetNameLoaded = true;\n                    }\n\n                    String name = senderName;\n                    if (!sender.equals(user)) {\n                        FriendData fd = m_messagesStore.getFriendData(user, sender);\n                        if (fd != null && !StringUtil.isNullOrEmpty(fd.getAlias())) {\n                            name = fd.getAlias();\n                        }\n                    }\n\n                    this.messageSender.sendPush(sender, conversationType, target, line, messageId, targetSession.getClientID(), pushContent, pushData, callStartUid, messageContentType, serverTime, name, senderPortrait, targetName, targetPortrait, m_messagesStore.getUnreceivedMsgCount(user), curMentionType, isHiddenDetail, targetSession.getLanguage(), getExistBadgeNumber(user));\n                }\n\n            }\n        }\n    }\n\n    private int getExistBadgeNumber(String user) {\n        int existBadgeNumber = 0;\n        WFCMessage.UserSettingEntry userSettingData = m_messagesStore.getUserSetting(user, UserSettingScope.kUserSettingScopeSyncBadge, \"\");\n        if(userSettingData != null && !StringUtil.isNullOrEmpty(userSettingData.getValue())) {\n            try {\n                existBadgeNumber = Integer.parseInt(userSettingData.getValue());\n            } catch (NumberFormatException e) {}\n        }\n        return existBadgeNumber;\n    }\n\n    public boolean sendOfflineNotify(String clientId) {\n        boolean targetIsActive = this.connectionDescriptors.isConnected(clientId);\n        if (targetIsActive) {\n            ByteBuf payload = Unpooled.buffer();\n            payload.ensureWritable(1).writeBytes(\"1\".getBytes());\n            MqttPublishMessage publishMsg;\n            publishMsg = notRetainedPublish(IMTopic.NotifyOffline, MqttQoS.AT_MOST_ONCE, payload);\n\n            boolean sent = this.messageSender.sendPublish(clientId, publishMsg);\n            if (sent) {\n                return true;\n            }\n        } else {\n            LOG.info(\"the target {} is not active\", clientId);\n        }\n\n        return false;\n    }\n\n    private void publishTransparentMessage2Receivers(long messageHead, Collection<String> receivers, int pullType, String exceptClientId) {\n        WFCMessage.Message message = m_messagesStore.getMessage(messageHead);\n\n        if (message != null) {\n            message = message.toBuilder().setMessageId(0).build();\n            for (String user : receivers) {\n                Collection<Session> sessions = m_sessionsStore.sessionForUser(user);\n\n                for (Session targetSession : sessions) {\n                    if(System.currentTimeMillis() - targetSession.getLastActiveTime() > 60 * 60 * 1000) {\n                        continue;\n                    }\n\n                    if (targetSession.getClientID() == null) {\n                        continue;\n                    }\n                    if (targetSession.getClientID().equals(exceptClientId)) {\n                        continue;\n                    }\n\n                    boolean targetIsActive = this.connectionDescriptors.isConnected(targetSession.getClientSession().clientID);\n                    if (targetIsActive) {\n                        ByteBuf payload = Unpooled.buffer();\n                        byte[] byteData = message.toByteArray();\n                        payload.ensureWritable(byteData.length).writeBytes(byteData);\n                        MqttPublishMessage publishMsg;\n                        publishMsg = notRetainedPublish(IMTopic.SendMessageTopic, MqttQoS.AT_MOST_ONCE, payload);\n\n                        this.messageSender.sendPublish(targetSession.getClientSession(), publishMsg);\n                    } else {\n                        LOG.info(\"the target {} of user {} is not active\", targetSession.getClientID(), targetSession.getUsername());\n                    }\n                }\n\n                if(sessions.isEmpty() && message.getContent().getType() == 403 && !user.equals(message.getFromUser())) {\n                    WFCMessage.User userInfo = m_messagesStore.getUserInfo(user);\n                    if (userInfo != null && userInfo.getType() == ProtoConstants.UserType.UserType_Robot) {\n                        WFCMessage.Robot robot = m_messagesStore.getRobot(user);\n                        if (robot != null && !StringUtil.isNullOrEmpty(robot.getCallback())) {\n                            OutputMessageData outputMessageData = getOutputMessageWithExtraInfo(message, exceptClientId, m_messagesStore.isRobotCallbackWithClientInfo() , m_messagesStore.isRobotCallbackWithSenderInfo(), m_messagesStore.isRobotCallbackWithTargetInfo());\n                            Server.getServer().getCallbackScheduler().execute(() -> {\n                                try {\n                                    HttpUtils.httpJsonPost(robot.getCallback(), GsonUtil.gson.toJson(outputMessageData, OutputMessageData.class), HttpUtils.HttpPostType.POST_TYPE_Robot_Message_Callback);\n                                } catch (Exception e) {\n                                    e.printStackTrace();\n                                    Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n                                }\n                            });\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    String getUserDisplayName(String userId, String groupId, List<String> portraitList) {\n        WFCMessage.User user = m_messagesStore.getUserInfo(userId);\n        String userName = null;\n        if(user != null) {\n            if(portraitList != null && !StringUtil.isNullOrEmpty(user.getPortrait())) {\n                portraitList.add(user.getPortrait());\n            }\n            userName = user.getDisplayName();\n        }\n        if (!StringUtil.isNullOrEmpty(groupId)) {\n            WFCMessage.GroupMember member = m_messagesStore.getGroupMember(groupId, userId);\n            if (member != null && !StringUtil.isNullOrEmpty(member.getAlias())) {\n                userName = member.getAlias();\n            }\n        }\n        return userName;\n    }\n\n    String getTargetName(String targetId, int cnvType, String fromUser, List<String> portraitList) {\n        if (cnvType == ConversationType_Private) {\n            return getUserDisplayName(targetId, null, portraitList);\n        } else if(cnvType == ConversationType_Group) {\n            WFCMessage.GroupInfo group = m_messagesStore.getGroupInfo(targetId);\n            if(group != null) {\n                if(!StringUtil.isNullOrEmpty(group.getPortrait())) {\n                    portraitList.add(group.getPortrait());\n                }\n\n                WFCMessage.UserSettingEntry entry = m_messagesStore.getUserSetting(fromUser, UserSettingScope.kUserSettingGroupRemark, targetId);\n                if(entry != null && !StringUtil.isNullOrEmpty(entry.getValue())) {\n                    return entry.getValue();\n                }\n                return group.getName();\n            }\n        } else if(cnvType == ConversationType_Channel) {\n            WFCMessage.ChannelInfo channelInfo = m_messagesStore.getChannelInfo(targetId);\n            if (channelInfo != null) {\n                if(!StringUtil.isNullOrEmpty(channelInfo.getPortrait())) {\n                    portraitList.add(channelInfo.getPortrait());\n                }\n                return channelInfo.getName();\n            }\n        }\n        return null;\n    }\n\n    public void publishNotification(String topic, String receiver, long head) {\n        publishNotification(topic, receiver, head, null, null);\n    }\n\n    public void publishNotification(String topic, String receiver, long head, String exceptClientId) {\n        publishNotification(topic, receiver, head, null, null, exceptClientId);\n    }\n\n    public void publishNotification(String topic, String receiver, long head, String fromUser, String pushContent) {\n        publishNotification(topic, receiver, head, fromUser, pushContent, null);\n    }\n    public void publishNotification(String topic, String receiver, long head, String fromUser, String pushContent, String exceptClientId) {\n        Collection<Session> sessions = m_sessionsStore.sessionForUser(receiver);\n        String fromUserName = null;\n        for (Session targetSession : sessions) {\n            if(targetSession.getClientID().equals(exceptClientId)) {\n                continue;\n            }\n\n            boolean needPush = !StringUtil.isNullOrEmpty(pushContent);\n            boolean targetIsActive = this.connectionDescriptors.isConnected(targetSession.getClientSession().clientID);\n            if (targetIsActive) {\n                ByteBuf payload = Unpooled.buffer();\n                payload.writeLong(head);\n                MqttPublishMessage publishMsg;\n                publishMsg = notRetainedPublish(topic, MqttQoS.AT_MOST_ONCE, payload);\n\n                boolean result = this.messageSender.sendPublish(targetSession.getClientSession(), publishMsg);\n                if (!result) {\n                    LOG.warn(\"Publish friend request failure\");\n                } else {\n                    needPush = false;\n                }\n            }\n            if (needPush) {\n                if (fromUserName == null) {\n                    WFCMessage.User userInfo = m_messagesStore.getUserInfo(fromUser);\n                    if (userInfo == null) {\n                        fromUserName = \"\";\n                    } else {\n                        fromUserName = userInfo.getDisplayName();\n                    }\n                }\n\n                if (IMTopic.NotifyFriendRequestTopic.equals(topic)) {\n                    messageSender.sendPush(fromUser, receiver, targetSession.getClientID(), pushContent, PushServer.PushMessageType.PUSH_MESSAGE_TYPE_FRIEND_REQUEST, System.currentTimeMillis(), fromUserName, m_messagesStore.getUnreceivedMsgCount(receiver) + 1, targetSession.getLanguage(), getExistBadgeNumber(receiver));\n                }\n            }\n        }\n    }\n\n    public void updateChatroomMembersQueue(String chatroomId, int line, long messageId) {\n        final long messageSeq = m_messagesStore.insertChatroomMessages(chatroomId, line, messageId);\n        Collection<UserClientEntry> members = m_messagesStore.getChatroomMembers(chatroomId);\n        for (UserClientEntry member : members\n             ) {\n            chatRoomHeaders.compute(member, new BiFunction<UserClientEntry, Long, Long>() {\n                @Override\n                public Long apply(UserClientEntry s, Long aLong) {\n                    if (aLong == null)\n                        return messageSeq;\n                    if (messageSeq > aLong)\n                        return messageSeq;\n                    return aLong;\n                }\n            });\n        }\n    }\n\n    public void publishRecall2ReceiversLocal(long messageUid, String operatorId, Collection<String> receivers, String exceptClientId) {\n        for (String user : receivers) {\n\n\n            Collection<Session> sessions = m_sessionsStore.sessionForUser(user);\n            for (Session targetSession : sessions) {\n                if (exceptClientId != null && exceptClientId.equals(targetSession.getClientSession().clientID)) {\n                    continue;\n                }\n\n                if (targetSession.getClientID() == null) {\n                    continue;\n                }\n\n                boolean targetIsActive = this.connectionDescriptors.isConnected(targetSession.getClientSession().clientID);\n                if (targetIsActive) {\n                    WFCMessage.NotifyRecallMessage notifyMessage = WFCMessage.NotifyRecallMessage\n                        .newBuilder()\n                        .setFromUser(operatorId)\n                        .setId(messageUid)\n                        .build();\n\n                    ByteBuf payload = Unpooled.buffer();\n                    byte[] byteData = notifyMessage.toByteArray();\n                    payload.ensureWritable(byteData.length).writeBytes(byteData);\n                    MqttPublishMessage publishMsg;\n                    publishMsg = notRetainedPublish(IMTopic.NotifyRecallMessageTopic, MqttQoS.AT_MOST_ONCE, payload);\n\n                    this.messageSender.sendPublish(targetSession.getClientSession(), publishMsg);\n                } else {\n                    LOG.info(\"the target {} of user {} is not active\", targetSession.getClientID(), targetSession.getUsername());\n                }\n            }\n        }\n    }\n\n    public void publishRecall2Receivers(long messageUid, String operatorId, Set<String> receivers, String exceptClientId) {\n        publishRecall2ReceiversLocal(messageUid, operatorId, receivers, exceptClientId);\n    }\n\n    public void publish2Receivers(WFCMessage.Message message, Set<String> receivers, String exceptClientId, int pullType) {\n        if (message.getConversation().getType() == ConversationType_Channel) {\n            WFCMessage.ChannelInfo channelInfo = m_messagesStore.getChannelInfo(message.getConversation().getTarget());\n\n            boolean forwardMsg;\n            if(m_messagesStore.isChannelNewCallbackFeature()) {\n                forwardMsg = channelInfo != null && !StringUtil.isNullOrEmpty(channelInfo.getCallback()) && !StringUtil.isNullOrEmpty(exceptClientId);\n            } else {\n                forwardMsg = channelInfo != null && !StringUtil.isNullOrEmpty(channelInfo.getCallback()) && channelInfo.getAutomatic() == 1 && !message.getFromUser().equals(channelInfo.getOwner());\n            }\n\n            if (forwardMsg) {\n                OutputMessageData outputMessageData = getOutputMessageWithExtraInfo(message, exceptClientId, m_messagesStore.isChannelCallbackWithClientInfo() , m_messagesStore.isChannelCallbackWithSenderInfo(), m_messagesStore.isChannelCallbackWithTargetInfo());\n                Server.getServer().getCallbackScheduler().execute(() -> {\n                    try {\n                        HttpUtils.httpJsonPost(channelInfo.getCallback() + \"/message\", GsonUtil.gson.toJson(outputMessageData, OutputMessageData.class), HttpUtils.HttpPostType.POST_TYPE_Channel_Message_Callback);\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                        Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n                    }\n                });\n            } else {\n                if (channelInfo == null) {\n                    LOG.info(\"Channel {} not exist\", message.getConversation().getTarget());\n                } else {\n                    LOG.info(\"Channel {} callback {}\", message.getConversation().getTarget(), channelInfo.getCallback());\n                }\n            }\n        }\n        long messageId = message.getMessageId();\n\n        String pushContent = message.getContent().getPushContent();\n        if (StringUtil.isNullOrEmpty(pushContent)) {\n            int type = message.getContent().getType();\n            if (type == ProtoConstants.ContentType.Image) {\n                pushContent = \"[图片]\";\n            } else if(type == ProtoConstants.ContentType.Location) {\n                pushContent = \"[位置]\";\n            } else if(type == ProtoConstants.ContentType.Text) {\n                pushContent = message.getContent().getSearchableContent();\n            } else if(type == ProtoConstants.ContentType.Voice) {\n                pushContent = \"[语音]\";\n            } else if(type == ProtoConstants.ContentType.Video) {\n                pushContent = \"[视频]\";\n            } else if(type == ProtoConstants.ContentType.Link) {\n                pushContent = \"[链接]\";\n            } else if(type == ProtoConstants.ContentType.File) {\n                pushContent = \"[文件]\";\n            } else if(type == ProtoConstants.ContentType.Sticker) {\n                pushContent = \"[表情]\";\n            } else if (type == ProtoConstants.ContentType.Name_Card) {\n                pushContent = \"[名片]\";\n            }\n        }\n\n        if (message.getContent().getPersistFlag() == Transparent) {\n            pushContent = null;\n        }\n\n        long callStartUid = 0;\n        if (message.getContent().getType() == 402) {\n            try {\n                String str = new String(message.getContent().getData().toByteArray(), StandardCharsets.UTF_8);\n                JSONObject jsonObject = (JSONObject)(new JSONParser().parse(str));\n                if (jsonObject.containsKey(\"u\")) {\n                    callStartUid = (Long)jsonObject.get(\"u\");\n                }\n            } catch (Exception e) {}\n        }\n\n\n        publish2Receivers(message.getFromUser(),\n                    message.getConversation().getType(), message.getConversation().getTarget(), message.getConversation().getLine(),\n                    messageId,\n                    receivers,\n                    pushContent, message.getContent().getPushData(), callStartUid, exceptClientId, pullType, message.getContent().getType(), message.getServerTimestamp(), message.getContent().getMentionedType(), message.getContent().getMentionedTargetList(), message.getContent().getPersistFlag(), message.hasToUser() || !message.getToList().isEmpty());\n\n    }\n\n    private OutputMessageData getOutputMessageWithExtraInfo(WFCMessage.Message message, String clientId, boolean withClient, boolean withSender, boolean withTarget) {\n        if (message == null) {\n            return null;\n        }\n\n        OutputClient outputClient = null;\n        if (withClient && !StringUtil.isNullOrEmpty(clientId)) {\n            Session session = m_sessionsStore.getSession(clientId);\n            if(session != null && session.getUsername().equals(message.getFromUser())) {\n                outputClient = new OutputClient(session.getPlatform(), clientId);\n            }\n        }\n\n        OutputMessageData outputMessageData = OutputMessageData.fromProtoMessage(message, outputClient);\n        if (withSender) {\n            WFCMessage.User senderInfo = m_messagesStore.getUserInfo(message.getFromUser());\n            outputMessageData.setSenderUserInfo(InputOutputUserInfo.fromPbUser(senderInfo));\n        }\n\n        if (withTarget) {\n            if (message.getConversation().getType() == ConversationType_Private) {\n                WFCMessage.User targetInfo = m_messagesStore.getUserInfo(message.getConversation().getTarget());\n                if (targetInfo != null) {\n                    outputMessageData.setTargetUserInfo(InputOutputUserInfo.fromPbUser(targetInfo));\n                }\n            } else if(message.getConversation().getType() == ConversationType_Group) {\n                WFCMessage.GroupInfo groupInfo = m_messagesStore.getGroupInfo(message.getConversation().getTarget());\n                if (groupInfo != null) {\n                    PojoGroupInfo pojoGroupInfo = new PojoGroupInfo();\n                    pojoGroupInfo.setExtra(groupInfo.getExtra());\n                    pojoGroupInfo.setName(groupInfo.getName());\n                    pojoGroupInfo.setOwner(groupInfo.getOwner());\n                    pojoGroupInfo.setPortrait(groupInfo.getPortrait());\n                    pojoGroupInfo.setTarget_id(groupInfo.getTargetId());\n                    pojoGroupInfo.setType(groupInfo.getType());\n                    pojoGroupInfo.setMember_count(groupInfo.getMemberCount());\n                    pojoGroupInfo.setMute(groupInfo.getMute());\n                    pojoGroupInfo.setJoin_type(groupInfo.getJoinType());\n                    pojoGroupInfo.setPrivate_chat(groupInfo.getPrivateChat());\n                    pojoGroupInfo.setSearchable(groupInfo.getSearchable());\n                    pojoGroupInfo.setMax_member_count(groupInfo.getMemberCount());\n                    pojoGroupInfo.setHistory_message(groupInfo.getHistoryMessage());\n                    pojoGroupInfo.setSuper_group(groupInfo.getSuperGroup()>0);\n                    pojoGroupInfo.setDeleted(groupInfo.getDeleted()>0);\n                    pojoGroupInfo.setUpdate_dt(groupInfo.getUpdateDt());\n                    pojoGroupInfo.setMember_update_dt(groupInfo.getMemberUpdateDt());\n                    outputMessageData.setTargetGroupInfo(pojoGroupInfo);\n                }\n            } else if(message.getConversation().getType() == ConversationType_Channel) {\n                WFCMessage.ChannelInfo targetInfo = m_messagesStore.getChannelInfo(message.getConversation().getTarget());\n                if (targetInfo != null) {\n                    outputMessageData.setTargetChannelInfo(OutputGetChannelInfo.fromPbInfo(targetInfo));\n                }\n            }\n        }\n\n        return outputMessageData;\n    }\n\n\n\n    public void forwardMessage(final WFCMessage.Message message, String forwardUrl, String fromClientId) {\n        OutputMessageData outputMessageData = getOutputMessageWithExtraInfo(message, fromClientId, m_messagesStore.isForwardMessageWithClientInfo() , m_messagesStore.isForwardMessageWithSenderInfo(), m_messagesStore.isForwardMessageWithTargetInfo());\n        Server.getServer().getCallbackScheduler().execute(() -> {\n            try {\n                HttpUtils.httpJsonPost(forwardUrl, GsonUtil.gson.toJson(outputMessageData), HttpUtils.HttpPostType.POST_TYPE_Forward_Message_Callback);\n            } catch (Exception e) {\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n            }\n        });\n    }\n\n    public void forwardMessageWithCallback(final WFCMessage.Message message, String fromClientId, String forwardUrl, HttpUtils.HttpCallback callback) {\n        OutputMessageData outputMessageData = getOutputMessageWithExtraInfo(message, fromClientId, m_messagesStore.isForwardMessageWithClientInfo() , m_messagesStore.isForwardMessageWithSenderInfo(), m_messagesStore.isForwardMessageWithTargetInfo());\n        try {\n            HttpUtils.httpJsonPost(forwardUrl, GsonUtil.gson.toJson(outputMessageData), new HttpUtils.HttpCallback() {\n                @Override\n                public void onSuccess(String content) {\n                    Server.getServer().getImBusinessScheduler().execute(()->{\n                        callback.onSuccess(content);\n                    });\n                }\n\n                @Override\n                public void onFailure(int statusCode, String errorMessage) {\n                    Server.getServer().getImBusinessScheduler().execute(()->{\n                        callback.onFailure(statusCode, errorMessage);\n                    });\n                }\n            }, HttpUtils.HttpPostType.POST_TYPE_Forward_Message_Callback);\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n        }\n    }\n\n    public void notifyChannelListenStatusChanged(WFCMessage.ChannelInfo channelInfo, String user, boolean listen) {\n        if (channelInfo == null || StringUtil.isNullOrEmpty(channelInfo.getCallback())) {\n            return;\n        }\n        if(!m_messagesStore.isChannelNewCallbackFeature() && channelInfo.getAutomatic() == 0) {\n            return;\n        }\n\n        Server.getServer().getCallbackScheduler().execute(() -> {\n            try {\n                HttpUtils.httpJsonPost(channelInfo.getCallback() + \"/subscribe\", GsonUtil.gson.toJson(new OutputNotifyChannelSubscribeStatus(user, channelInfo.getTargetId(), listen), OutputNotifyChannelSubscribeStatus.class), HttpUtils.HttpPostType.POST_TYPE_Channel_Subscriber_Event_Callback);\n            } catch (Exception e) {\n                e.printStackTrace();\n                Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/PersistentQueueMessageSender.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.push.PushMessage;\nimport cn.wildfirechat.push.PushServer;\nimport io.moquette.server.ConnectionDescriptorStore;\nimport io.moquette.spi.ClientSession;\nimport io.netty.handler.codec.mqtt.MqttPublishMessage;\nimport io.netty.handler.codec.mqtt.MqttQoS;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport static io.moquette.spi.impl.ProtocolProcessor.asStoredMessage;\nimport static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE;\n\nclass PersistentQueueMessageSender {\n\n    private static final Logger LOG = LoggerFactory.getLogger(PersistentQueueMessageSender.class);\n    private final ConnectionDescriptorStore connectionDescriptorStore;\n\n    PersistentQueueMessageSender(ConnectionDescriptorStore connectionDescriptorStore) {\n        this.connectionDescriptorStore = connectionDescriptorStore;\n    }\n\n    void sendPush(String sender, int conversationType, String target, int line, long messageId, String deviceId, String pushContent, String pushData, long callStartUid, int messageContentType, long serverTime, String senderName, String senderPortrait, String targetName, String targetPortrait, int unReceivedMsg, int mentionType, boolean isHiddenDetail, String language, int existBadgeNumber) {\n        LOG.info(\"Send push to {}, message from {}\", deviceId, sender);\n        PushMessage pushMessage = new PushMessage(sender, conversationType, target, line, messageContentType, serverTime, senderName, senderPortrait, targetName, targetPortrait, unReceivedMsg, mentionType, isHiddenDetail, language);\n        pushMessage.pushContent = pushContent;\n        pushMessage.pushData = pushData;\n        pushMessage.messageId = messageId;\n        pushMessage.callStartUid = callStartUid;\n        pushMessage.existBadgeNumber = existBadgeNumber;\n        PushServer.getServer().pushMessage(pushMessage, deviceId, pushContent);\n    }\n\n    void sendPush(String sender, String target, String deviceId, String pushContent, int pushContentType, long serverTime, String senderName, int unReceivedMsg, String language, int existBadgeNumber) {\n        LOG.info(\"Send push to {}, message from {}\", deviceId, sender);\n        PushMessage pushMessage = new PushMessage(sender, target, serverTime, senderName, unReceivedMsg, language, pushContentType);\n        pushMessage.pushContent = pushContent;\n        PushServer.getServer().pushMessage(pushMessage, deviceId, pushContent);\n    }\n\n    boolean sendPublish(ClientSession clientsession, MqttPublishMessage pubMessage) {\n        String clientId = clientsession.clientID;\n        return sendPublish(clientId, pubMessage);\n    }\n\n    boolean sendPublish(String clientId, MqttPublishMessage pubMessage) {\n        final int messageId = pubMessage.variableHeader().packetId();\n        final String topicName = pubMessage.variableHeader().topicName();\n        if (LOG.isDebugEnabled()) {\n            LOG.debug(\"Sending PUBLISH message. MessageId={}, CId={}, topic={}, qos={}, payload={}\", messageId,\n                clientId, topicName, DebugUtils.payload2Str(pubMessage.payload()));\n        } else {\n            LOG.info(\"Sending PUBLISH message. MessageId={}, CId={}, topic={}\", messageId, clientId, topicName);\n        }\n\n        boolean messageDelivered = connectionDescriptorStore.sendMessage(pubMessage, messageId, clientId, null);\n\n        if(!messageDelivered) {\n            LOG.warn(\"PUBLISH message could not be delivered.  MessageId={}, CId={}, topic={}\", messageId, clientId, topicName);\n        }\n\n        return messageDelivered;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/ProtocolProcessor.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.OutputCheckUserOnline;\nimport cn.wildfirechat.pojos.UserOnlineStatus;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.BrokerConstants;\nimport io.moquette.persistence.ServerAPIHelper;\nimport io.moquette.interception.InterceptHandler;\nimport io.moquette.interception.messages.InterceptAcknowledgedMessage;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.moquette.server.ConnectionDescriptor;\nimport io.moquette.server.ConnectionDescriptorStore;\nimport io.moquette.server.Server;\nimport io.moquette.server.netty.NettyUtils;\nimport io.moquette.spi.*;\nimport io.moquette.spi.IMessagesStore.StoredMessage;\nimport io.moquette.spi.impl.security.AES;\nimport io.moquette.spi.security.IAuthenticator;\nimport io.moquette.spi.security.IAuthorizator;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelPipeline;\nimport io.netty.handler.codec.mqtt.*;\nimport io.netty.handler.timeout.IdleStateHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.GsonUtil;\nimport win.liyufan.im.HttpUtils;\nimport win.liyufan.im.IMTopic;\nimport win.liyufan.im.Utility;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport static cn.wildfirechat.common.ErrorCode.ERROR_CODE_SUCCESS;\nimport static io.moquette.spi.impl.InternalRepublisher.createPublishForQos;\nimport static cn.wildfirechat.common.IMExceptionEvent.EventType.EVENT_CALLBACK_Exception;\nimport static io.moquette.spi.impl.Utils.readBytesAndRewind;\nimport static io.netty.handler.codec.mqtt.MqttConnectReturnCode.*;\nimport static io.netty.handler.codec.mqtt.MqttMessageIdVariableHeader.from;\nimport static io.netty.handler.codec.mqtt.MqttQoS.*;\nimport static io.moquette.server.ConnectionDescriptor.ConnectionState.*;\n\n/**\n * Class responsible to handle the logic of MQTT protocol it's the director of the protocol\n * execution.\n *\n * Used by the front facing class ProtocolProcessorBootstrapper.\n */\n\npublic class ProtocolProcessor {\n    private static ExecutorService executorCallback = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());\n\n    public void kickoffSession(final MemorySessionStore.Session session) {\n        mServer.getImBusinessScheduler().execute(()->{\n            new Thread(() -> {\n                messagesPublisher.sendOfflineNotify(session.getClientID());\n                try {\n                    Thread.sleep(3000);\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n\n                mServer.getImBusinessScheduler().execute(()->{\n                    ConnectionDescriptor descriptor = connectionDescriptors.getConnection(session.getClientID());\n                    try {\n                        if (descriptor != null) {\n                            processDisconnect(descriptor.getChannel(), true, false);\n                        }\n                    } catch (InterruptedException e) {\n                        e.printStackTrace();\n                        Utility.printExecption(LOG, e);\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                        Utility.printExecption(LOG, e);\n                    }\n                    m_messagesStore.updateUserOnlineSetting(session, false);\n                });\n            }).start();\n        });\n    }\n\n    private void kickoffUserOffline(String userId) {\n        System.out.println(\"kickoff user \" + userId);\n            Collection<MemorySessionStore.Session> sessions = m_sessionsStore.sessionForUser(userId);\n            for (MemorySessionStore.Session session : sessions) {\n                ConnectionDescriptor descriptor = connectionDescriptors.getConnection(session.getClientID());\n                try {\n                    if (descriptor != null) {\n                        processDisconnect(descriptor.getChannel(), false, false);\n                    }\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e);\n                }\n            }\n    }\n\n\n    private static final Logger LOG = LoggerFactory.getLogger(ProtocolProcessor.class);\n\n    protected ConnectionDescriptorStore connectionDescriptors;\n\n    private IAuthorizator m_authorizator;\n\n    private IMessagesStore m_messagesStore;\n\n    private ISessionsStore m_sessionsStore;\n\n    private IAuthenticator m_authenticator;\n    private BrokerInterceptor m_interceptor;\n\n    public Qos1PublishHandler qos1PublishHandler;\n    private MessagesPublisher messagesPublisher;\n\n    private Server mServer;\n\n    ProtocolProcessor() {\n\n    }\n\n    /**\n     * @param storageService\n     *            the persistent store to use for save/load of messages for QoS1 and QoS2 handling.\n     * @param sessionsStore\n     *            the clients sessions store, used to persist subscriptions.\n     * @param authenticator\n     *            true to allow clients connect without a clientid\n     * @param authorizator\n     *            used to apply ACL policies to publishes and subscriptions.\n     * @param interceptor\n     *            to notify events to an intercept handler\n     */\n    void init(ConnectionDescriptorStore connectionDescriptors,\n              IMessagesStore storageService, ISessionsStore sessionsStore, IAuthenticator authenticator, IAuthorizator authorizator,\n              BrokerInterceptor interceptor, Server server) {\n        LOG.info(\"Initializing MQTT protocol processor...\");\n        this.connectionDescriptors = connectionDescriptors;\n        this.m_interceptor = interceptor;\n        m_authorizator = authorizator;\n        m_authenticator = authenticator;\n        m_messagesStore = storageService;\n        m_sessionsStore = sessionsStore;\n\n        LOG.info(\"Initializing messages publisher...\");\n        final PersistentQueueMessageSender messageSender = new PersistentQueueMessageSender(this.connectionDescriptors);\n        this.messagesPublisher = new MessagesPublisher(connectionDescriptors, sessionsStore, messageSender, server.getHazelcastInstance(), m_messagesStore);\n\n        LOG.info(\"Initializing QoS publish handlers...\");\n        this.qos1PublishHandler = new Qos1PublishHandler(m_authorizator, m_messagesStore, m_interceptor,\n                this.connectionDescriptors, this.messagesPublisher, sessionsStore, server.getImBusinessScheduler(), server);\n\n        mServer = server;\n\n        String onlineStatusCallback = server.getConfig().getProperty(BrokerConstants.USER_ONLINE_STATUS_CALLBACK);\n        if (!com.hazelcast.util.StringUtil.isNullOrEmpty(onlineStatusCallback)) {\n            mUserOnlineStatusCallback = onlineStatusCallback;\n        }\n    }\n\n    private String mUserOnlineStatusCallback;\n\n    public void processConnect(Channel channel, MqttConnectMessage msg) {\n        MqttConnectPayload payload = msg.payload();\n        String clientId = payload.clientIdentifier();\n        LOG.info(\"Processing CONNECT message. CId={}, username={}\", clientId, payload.userName());\n\n        if (msg.variableHeader().version() < MqttVersion.MQTT_3_1_1.protocolLevel()) {\n            MqttConnAckMessage badProto = connAck(CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION);\n\n            LOG.error(\"MQTT protocol version is not valid. CId={}\", clientId);\n            channel.writeAndFlush(badProto);\n            channel.close();\n            return;\n        }\n\n        if (clientId == null || clientId.length() == 0) {\n            MqttConnAckMessage badId = connAck(CONNECTION_REFUSED_IDENTIFIER_REJECTED);\n\n            channel.writeAndFlush(badId);\n            channel.close();\n            LOG.error(\"The MQTT client ID cannot be empty. Username={}\", payload.userName());\n            return;\n        }\n\n\n        MqttVersion mqttVersion = MqttVersion.fromProtocolLevel(msg.variableHeader().version());\n        if (!login(channel, msg, clientId, mqttVersion)) {\n            channel.flush();\n            channel.close();\n            LOG.error(\"The MQTT login failure. Username={}\", payload.userName());\n            return;\n        }\n        if (!mServer.m_initialized) {\n            channel.close();\n            return;\n        }\n\n        ConnectionDescriptor descriptor = new ConnectionDescriptor(clientId, channel);\n        ConnectionDescriptor existing = this.connectionDescriptors.addConnection(descriptor);\n        if (existing != null) {\n            LOG.info(\"The client ID is being used in an existing connection. It will be closed. CId={}\", clientId);\n            this.connectionDescriptors.removeConnection(existing);\n            existing.abort();\n            this.connectionDescriptors.addConnection(descriptor);\n        }\n\n        initializeKeepAliveTimeout(channel, msg, clientId);\n        if (!sendAck(descriptor, msg, clientId)) {\n            channel.close();\n            return;\n        }\n\n        m_interceptor.notifyClientConnected(msg);\n\n        final ClientSession clientSession = createOrLoadClientSession(payload.userName(), descriptor, msg, clientId);\n        if (clientSession == null) {\n            MqttConnAckMessage badId = connAck(CONNECTION_REFUSED_SESSION_NOT_EXIST);\n\n            channel.writeAndFlush(badId);\n            channel.close();\n            return;\n        }\n\n\n        int flushIntervalMs = 500/* (keepAlive * 1000) / 2 */;\n        descriptor.setupAutoFlusher(flushIntervalMs);\n\n        final boolean success = descriptor.assignState(SESSION_CREATED, ESTABLISHED);\n        if (!success) {\n            channel.close();\n            return;\n        }\n        MemorySessionStore.Session session = m_sessionsStore.getSession(clientId);\n        if(session != null) {\n            session.refreshLastActiveTime();\n            forwardOnlineStatusEvent(payload.userName(), clientId, session.getPlatform(), UserOnlineStatus.ONLINE, session.getAppName());\n            m_messagesStore.updateUserOnlineSetting(session, true);\n        }\n\n        LOG.info(\"The CONNECT message has been processed. CId={}, username={}\", clientId, payload.userName());\n    }\n\n    public void forwardOnlineStatusEvent(String userId, String clientId, int platform, int status, String packageName) {\n        if (!StringUtil.isNullOrEmpty(mUserOnlineStatusCallback)) {\n            mServer.getCallbackScheduler().execute(() -> {\n                try {\n                    int sessionstatus;\n                    Collection<MemorySessionStore.Session> useSessions = m_sessionsStore.sessionForUser(userId);\n                    UserOnlineStatus userOnlineStatus = new UserOnlineStatus(userId, clientId, platform, status, packageName);\n                    userOnlineStatus.sessions = new ArrayList<>();\n\n                    for (MemorySessionStore.Session session : useSessions) {\n                        if (session.getDeleted() > 0) {\n                            continue;\n                        }\n\n                        ConnectionDescriptor descriptor = connectionDescriptors.getConnection(session.getClientID());\n                        if (descriptor == null) {\n                            sessionstatus = 1;\n                        } else {\n                            sessionstatus = 0;\n                        }\n\n                        userOnlineStatus.sessions.add(new OutputCheckUserOnline.Session(userId, session.getClientID(), session.getPlatform(), sessionstatus, session.getLastActiveTime(), session.getAppName(), session.getIp()));\n                    }\n\n                    HttpUtils.httpJsonPost(mUserOnlineStatusCallback, GsonUtil.gson.toJson(userOnlineStatus), HttpUtils.HttpPostType.POST_TYPE_User_Online_Event_Callback);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e, EVENT_CALLBACK_Exception);\n                }\n            });\n        }\n    }\n\n    private MqttConnAckMessage connAck(MqttConnectReturnCode returnCode) {\n        return connAck(returnCode, false);\n    }\n\n    private MqttConnAckMessage connAck(MqttConnectReturnCode returnCode, boolean sessionPresent) {\n        return connAck(returnCode, sessionPresent, null);\n    }\n\n    private MqttConnAckMessage connAck(MqttConnectReturnCode returnCode, byte[] data) {\n        return connAck(returnCode, false, data);\n    }\n\n\n    private MqttConnAckMessage connAckWithSessionPresent(MqttConnectReturnCode returnCode, byte[] data) {\n        return connAck(returnCode, true, data);\n    }\n\n\n    private MqttConnAckMessage connAck(MqttConnectReturnCode returnCode, boolean sessionPresent, byte[] data) {\n        MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.CONNACK, false, MqttQoS.AT_MOST_ONCE,\n            false, 0);\n        MqttConnAckVariableHeader mqttConnAckVariableHeader = new MqttConnAckVariableHeader(returnCode, sessionPresent);\n        return new MqttConnAckMessage(mqttFixedHeader, mqttConnAckVariableHeader, new MqttConnectAckPayload(data));\n    }\n    private boolean login(Channel channel, MqttConnectMessage msg, final String clientId, MqttVersion mqttVersion) {\n        // handle user authentication\n        if (msg.variableHeader().hasUserName()) {\n            int status = m_messagesStore.getUserStatus(msg.payload().userName());\n            if (status == ProtoConstants.UserStatus.Forbidden) {\n                failedBlocked(channel);\n                return false;\n            }\n            byte[] pwd = null;\n            if (msg.variableHeader().hasPassword()) {\n                pwd = msg.payload().passwordInBytes();\n\n                MemorySessionStore.Session session = m_sessionsStore.getSession(clientId);\n                if (session == null) {\n                    ErrorCode errorCode = m_sessionsStore.loadActiveSession(msg.payload().userName(), clientId);\n                    if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {\n                        failedNoSession(channel);\n                        return false;\n                    }\n                    session = m_sessionsStore.getSession(clientId);\n                }\n\n                if (session.getDeleted() != 0) {\n                    LOG.error(\"user {} session {} is deleted. login failure\", msg.payload().userName(), clientId);\n                    failedNoSession(channel);\n                    return false;\n                }\n                \n                if (session != null && session.getUsername().equals(msg.payload().userName())) {\n                    pwd = AES.AESDecrypt(pwd, session.getSecret(), true);\n                } else {\n                    LOG.error(\"Password decrypt failed of client {}\", clientId);\n                    failedNoSession(channel);\n                    return false;\n                }\n\n                if (pwd == null) {\n                    LOG.error(\"Password decrypt failed of client {}\", clientId);\n                    failedCredentials(channel);\n                    return false;\n                }\n\n                if(session.getPlatform() == ProtoConstants.Platform.Platform_Android || session.getPlatform() == ProtoConstants.Platform.Platform_APad) {\n                    byte[] signature = msg.payload().signatureInBytes();\n                    String basedSign = null;\n                    if (signature != null && signature.length > 0) {\n                        signature = AES.AESDecrypt(signature, session.getSecret(), true);\n                    }\n                    if (signature != null && signature.length > 0) {\n                        basedSign = Base64.getEncoder().encodeToString(signature);\n                    }\n\n                    if (!m_messagesStore.checkSignature(basedSign)) {\n                        LOG.error(\"Bad signature of session <{}, {}>\", session.getUsername(), session.getClientID());\n                        failedBadSignature(channel);\n                        return false;\n                    }\n                }\n\n                session.setMqttVersion(mqttVersion);\n            } else {\n                LOG.error(\"Client didn't supply any password and MQTT anonymous mode is disabled CId={}\", clientId);\n                failedCredentials(channel);\n                return false;\n            }\n            if (!m_authenticator.checkValid(clientId, msg.payload().userName(), pwd)) {\n                LOG.error(\"Authenticator has rejected the MQTT credentials CId={}, username={}, password={}\",\n                        clientId, msg.payload().userName(), pwd);\n                failedCredentials(channel);\n                return false;\n            }\n            NettyUtils.userName(channel, msg.payload().userName());\n            return true;\n        } else {\n            LOG.error(\"Client didn't supply any credentials and MQTT anonymous mode is disabled. CId={}\", clientId);\n            failedCredentials(channel);\n            return false;\n        }\n    }\n\n    private boolean sendAck(ConnectionDescriptor descriptor, MqttConnectMessage msg, final String clientId) {\n        LOG.info(\"Sending connect ACK. CId={}\", clientId);\n        final boolean success = descriptor.assignState(DISCONNECTED, SENDACK);\n        if (!success) {\n            return false;\n        }\n\n        MqttConnAckMessage okResp;\n        ClientSession clientSession = m_sessionsStore.sessionForClient(clientId);\n        boolean isSessionAlreadyStored = clientSession != null;\n\n        String user = msg.payload().userName();\n        long messageHead = m_messagesStore.getMessageHead(user);\n        long friendHead = m_messagesStore.getFriendHead(user);\n        long friendRqHead = m_messagesStore.getFriendRqHead(user);\n        long settingHead = m_messagesStore.getSettingHead(user);\n        WFCMessage.ConnectAckPayload payload = WFCMessage.ConnectAckPayload.newBuilder()\n            .setMsgHead(messageHead)\n            .setFriendHead(friendHead)\n            .setFriendRqHead(friendRqHead)\n            .setSettingHead(settingHead)\n            .setServerTime(System.currentTimeMillis())\n            .build();\n\n\n        if (!msg.variableHeader().isCleanSession() && isSessionAlreadyStored) {\n            okResp = connAckWithSessionPresent(CONNECTION_ACCEPTED, payload.toByteArray());\n        } else {\n            okResp = connAck(CONNECTION_ACCEPTED, payload.toByteArray());\n        }\n\n        descriptor.writeAndFlush(okResp);\n        LOG.info(\"The connect ACK has been sent. CId={}\", clientId);\n        return true;\n    }\n\n    private void initializeKeepAliveTimeout(Channel channel, MqttConnectMessage msg, final String clientId) {\n        int keepAlive = msg.variableHeader().keepAliveTimeSeconds();\n        LOG.info(\"Configuring connection. CId={}\", clientId);\n        NettyUtils.keepAlive(channel, keepAlive);\n        // session.attr(NettyUtils.ATTR_KEY_CLEANSESSION).set(msg.variableHeader().isCleanSession());\n        NettyUtils.cleanSession(channel, msg.variableHeader().isCleanSession());\n        // used to track the client in the subscription and publishing phases.\n        // session.attr(NettyUtils.ATTR_KEY_CLIENTID).set(msg.getClientID());\n        NettyUtils.clientID(channel, clientId);\n        int idleTime = Math.round(keepAlive * 1.5f);\n        setIdleTime(channel.pipeline(), idleTime);\n\n        LOG.debug(\"The connection has been configured CId={}, keepAlive={}, cleanSession={}, idleTime={}\",\n                clientId, keepAlive, msg.variableHeader().isCleanSession(), idleTime);\n    }\n\n    private ClientSession createOrLoadClientSession(String username, ConnectionDescriptor descriptor, MqttConnectMessage msg,\n            String clientId) {\n        final boolean success = descriptor.assignState(SENDACK, SESSION_CREATED);\n        if (!success) {\n            return null;\n        }\n\n        m_sessionsStore.loadUserSession(username, clientId);\n        ClientSession clientSession = m_sessionsStore.sessionForClient(clientId);\n        boolean isSessionAlreadyStored = clientSession != null;\n        if (isSessionAlreadyStored) {\n            clientSession = m_sessionsStore.updateExistSession(username, clientId, null, msg.variableHeader().isCleanSession());\n        } else {\n            return null;\n        }\n\n        return clientSession;\n    }\n\n    private void failedBlocked(Channel session) {\n        session.writeAndFlush(connAck(CONNECTION_REFUSED_IDENTIFIER_REJECTED));\n        LOG.info(\"Client {} failed to connect, use is blocked.\", session);\n    }\n\n    private void failedCredentials(Channel session) {\n        session.writeAndFlush(connAck(CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD));\n        LOG.info(\"Client {} failed to connect with bad username or password.\", session);\n    }\n\n    private void failedNoSession(Channel session) {\n        session.writeAndFlush(connAck(CONNECTION_REFUSED_SESSION_NOT_EXIST));\n        LOG.info(\"Client {} failed to connect with bad username or password.\", session);\n    }\n\n    private void failedBadSignature(Channel session) {\n        session.writeAndFlush(connAck(CONNECTION_REFUSED_SIGNATURE_FAILURE));\n        LOG.info(\"Client {} failed to connect with bad signature.\", session);\n    }\n\n    private void setIdleTime(ChannelPipeline pipeline, int idleTime) {\n        if (pipeline.names().contains(\"idleStateHandler\")) {\n            pipeline.remove(\"idleStateHandler\");\n        }\n        pipeline.addFirst(\"idleStateHandler\", new IdleStateHandler(idleTime, 0, 0));\n    }\n\n    public void processPubAck(Channel channel, MqttPubAckMessage msg) {\n        String clientID = NettyUtils.clientID(channel);\n        int messageID = msg.variableHeader().messageId();\n        String username = NettyUtils.userName(channel);\n        LOG.trace(\"retrieving inflight for messageID <{}>\", messageID);\n\n        ClientSession targetSession = m_sessionsStore.sessionForClient(clientID);\n        StoredMessage inflightMsg = targetSession.inFlightAcknowledged(messageID);\n\n        String topic = inflightMsg.getTopic();\n        InterceptAcknowledgedMessage wrapped = new InterceptAcknowledgedMessage(inflightMsg, topic, username, messageID);\n        m_interceptor.notifyMessageAcknowledged(wrapped);\n    }\n\n    public static IMessagesStore.StoredMessage asStoredMessage(MqttPublishMessage msg) {\n        // TODO ugly, too much array copy\n        ByteBuf payload = msg.payload();\n        byte[] payloadContent = readBytesAndRewind(payload);\n\n        IMessagesStore.StoredMessage stored = new IMessagesStore.StoredMessage(payloadContent,\n                msg.fixedHeader().qosLevel(), msg.variableHeader().topicName());\n        stored.setRetained(msg.fixedHeader().isRetain());\n        return stored;\n    }\n\n    public void processPublish(Channel channel, MqttPublishMessage msg) {\n        final MqttQoS qos = msg.fixedHeader().qosLevel();\n        final String clientId = NettyUtils.clientID(channel);\n        \n        LOG.info(\"Processing PUBLISH message. CId={}, topic={}, messageId={}, qos={}\", clientId,\n                msg.variableHeader().topicName(), msg.variableHeader().packetId(), qos);\n        switch (qos) {\n            case AT_MOST_ONCE:\n                //not support\n                break;\n            case AT_LEAST_ONCE:\n                this.qos1PublishHandler.receivedPublishQos1(channel, msg);\n                break;\n            case EXACTLY_ONCE:\n                //not use\n                break;\n            default:\n                LOG.error(\"Unknown QoS-Type:{}\", qos);\n                break;\n        }\n    }\n\n    /**\n     * Second phase of a publish QoS2 protocol, sent by publisher to the broker. Search the stored\n     * message and publish to all interested subscribers.\n     *\n     * @param channel\n     *            the channel of the incoming message.\n     * @param msg\n     *            the decoded pubrel message.\n     */\n    public void processPubRel(Channel channel, MqttMessage msg) {\n        //not use\n    }\n\n    public void processPubRec(Channel channel, MqttMessage msg) {\n        //not use\n    }\n\n    public void processPubComp(Channel channel, MqttMessage msg) {\n       //not use\n    }\n\n    public void processDisconnect(Channel channel, boolean isDup, boolean isRetain) throws InterruptedException {\n        final String clientID = NettyUtils.clientID(channel);\n        LOG.info(\"Processing DISCONNECT message. CId={}, clearSession={}\", clientID, isDup);\n        channel.flush();\n\n        if (clientID == null) {\n            LOG.error(\"Error. Cid not exist!!!\", clientID, isDup);\n            channel.close();\n            return;\n        }\n\n        if (!isDup && !isRetain) {\n            processConnectionLost(clientID, channel, isDup);\n            return;\n        }\n\n\n        final ConnectionDescriptor existingDescriptor = this.connectionDescriptors.getConnection(clientID);\n        if (existingDescriptor == null) {\n            // another client with same ID removed the descriptor, we must exit\n            channel.close();\n            return;\n        }\n\n        if (existingDescriptor.doesNotUseChannel(channel)) {\n            // another client saved it's descriptor, exit\n            LOG.warn(\"Another client is using the connection descriptor. Closing connection. CId={}\", clientID);\n            existingDescriptor.abort();\n            return;\n        }\n\n\n        if (!dropStoredMessages(existingDescriptor, clientID)) {\n            LOG.warn(\"Unable to drop stored messages. Closing connection. CId={}\", clientID);\n            existingDescriptor.abort();\n            return;\n        }\n\n        if (!notifyInterceptorDisconnected(existingDescriptor, clientID)) {\n            LOG.warn(\"Unable to drop will message. Closing connection. CId={}\", clientID);\n            existingDescriptor.abort();\n            return;\n        }\n\n        if (!existingDescriptor.close()) {\n            LOG.info(\"The connection has been closed. CId={}\", clientID);\n            return;\n        }\n\n        this.connectionDescriptors.removeConnection(existingDescriptor);\n\n        LOG.info(\"The DISCONNECT message has been processed. CId={}\", clientID);\n\n        String username = NettyUtils.userName(channel);\n        MemorySessionStore.Session session = m_sessionsStore.getSession(clientID);\n        if(session != null) {\n            m_messagesStore.updateUserOnlineSetting(session, false);\n            forwardOnlineStatusEvent(username, clientID, session.getPlatform(), UserOnlineStatus.LOGOUT, session.getAppName());\n        }\n\n        channel.closeFuture();\n\n        //disconnect the session\n        if(session != null) {\n            m_sessionsStore.sessionForClient(clientID).disconnect(session.getUsername(), isDup, isRetain);\n        }\n    }\n\n\n    private boolean dropStoredMessages(ConnectionDescriptor descriptor, String clientID) {\n        final boolean success = descriptor.assignState(ESTABLISHED, MESSAGES_DROPPED);\n        if (!success) {\n            return false;\n        }\n\n        LOG.debug(\"Removing messages of session. CId={}\", descriptor.clientID);\n        this.m_sessionsStore.dropQueue(clientID);\n        LOG.debug(\"The messages of the session have been removed. CId={}\", descriptor.clientID);\n\n        return true;\n    }\n\n    private boolean notifyInterceptorDisconnected(ConnectionDescriptor descriptor, String clientID) {\n        final boolean success = descriptor.assignState(MESSAGES_DROPPED, INTERCEPTORS_NOTIFIED);\n        if (!success) {\n            return false;\n        }\n\n        LOG.info(\"Removing will message. ClientId={}\", descriptor.clientID);\n        // cleanup the will store\n        String username = descriptor.getUsername();\n        m_interceptor.notifyClientDisconnected(clientID, username);\n        return true;\n    }\n\n    public void processConnectionLost(String clientID, Channel channel, boolean clearSession) {\n        LOG.info(\"Processing connection lost event. CId={}\", clientID);\n\n        String username = NettyUtils.userName(channel);\n        MemorySessionStore.Session session = m_sessionsStore.getSession(clientID);\n        if(session != null) {\n            processOffline(session, clearSession, () -> {\n                ConnectionDescriptor oldConnDescr = new ConnectionDescriptor(clientID, channel);\n                if(connectionDescriptors.removeConnection(oldConnDescr)) {\n                    m_interceptor.notifyClientConnectionLost(clientID, username);\n                }\n                try {\n                    channel.close();\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            });\n        } else {\n            ConnectionDescriptor oldConnDescr = new ConnectionDescriptor(clientID, channel);\n            if(connectionDescriptors.removeConnection(oldConnDescr)) {\n                m_interceptor.notifyClientConnectionLost(clientID, username);\n            }\n            try {\n                channel.close();\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public void processOffline(MemorySessionStore.Session session, boolean logout, Runnable runnable) {\n        if(session != null) {\n            session.refreshLastActiveTime();\n            forwardOnlineStatusEvent(session.getUsername(), session.getClientID(), session.getPlatform(), logout ? UserOnlineStatus.LOGOUT : UserOnlineStatus.OFFLINE, session.getAppName());\n            if(runnable != null) {\n                runnable.run();\n            }\n            m_messagesStore.updateUserOnlineSetting(session, false);\n        }\n    }\n\n    /**\n     * Remove the clientID from topic subscription, if not previously subscribed, doesn't reply any\n     * error.\n     *\n     * @param channel\n     *            the channel of the incoming message.\n     * @param msg\n     *            the decoded unsubscribe message.\n     */\n    public void processUnsubscribe(Channel channel, MqttUnsubscribeMessage msg) {\n        //Not use\n    }\n\n    public void processSubscribe(Channel channel, MqttSubscribeMessage msg) {\n        //not use\n    }\n\n\n    /**\n     * Create the SUBACK response from a list of topicFilters\n     */\n    private MqttSubAckMessage doAckMessageFromValidateFilters(List<MqttTopicSubscription> topicFilters, int messageId) {\n        List<Integer> grantedQoSLevels = new ArrayList<>();\n        for (MqttTopicSubscription req : topicFilters) {\n            grantedQoSLevels.add(req.qualityOfService().value());\n        }\n\n        MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.SUBACK, false, AT_LEAST_ONCE, false, 0);\n        MqttSubAckPayload payload = new MqttSubAckPayload(grantedQoSLevels);\n        return new MqttSubAckMessage(fixedHeader, from(messageId), payload);\n    }\n\n    public void notifyChannelWritable(Channel channel) {\n        String clientID = NettyUtils.clientID(channel);\n        ClientSession clientSession = m_sessionsStore.sessionForClient(clientID);\n        boolean emptyQueue = false;\n        while (channel.isWritable() && !emptyQueue) {\n            StoredMessage msg = clientSession.queue().poll();\n            if (msg == null) {\n                emptyQueue = true;\n            } else {\n                // recreate a publish from stored publish in queue\n                MqttPublishMessage pubMsg = createPublishForQos( msg.getTopic(), msg.getQos(), msg.getPayload(),\n                        msg.isRetained(), 0);\n                channel.write(pubMsg);\n            }\n        }\n        channel.flush();\n    }\n\n    public ConnectionDescriptorStore getConnectionDescriptors() {\n        return connectionDescriptors;\n    }\n\n    public void addInterceptHandler(InterceptHandler interceptHandler) {\n        this.m_interceptor.addInterceptHandler(interceptHandler);\n    }\n\n    public void removeInterceptHandler(InterceptHandler interceptHandler) {\n        this.m_interceptor.removeInterceptHandler(interceptHandler);\n    }\n\n    public IMessagesStore getMessagesStore() {\n        return m_messagesStore;\n    }\n\n    public ISessionsStore getSessionsStore() {\n        return m_sessionsStore;\n    }\n\n    public void onApiMessage(String fromUser, String clientId, byte[] message, int messageId, String from, String request, ProtoConstants.RequestSourceType requestSourceType) {\n        if(request.equals(ServerAPIHelper.KICKOFF_USER_REQUEST)) {\n            String userId = new String(message);\n            mServer.getImBusinessScheduler().execute(()-> kickoffUserOffline(userId));\n            return;\n        }\n        qos1PublishHandler.onApiMessage(fromUser, clientId, message, messageId, from, request, requestSourceType);\n    }\n    public void shutdown() {\n        messagesPublisher.stopChatroomScheduler();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/ProtocolProcessorBootstrapper.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl;\n\nimport java.lang.reflect.InvocationTargetException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport io.moquette.BrokerConstants;\nimport io.moquette.interception.InterceptHandler;\nimport io.moquette.server.ConnectionDescriptorStore;\nimport io.moquette.server.Server;\nimport io.moquette.server.config.IConfig;\nimport io.moquette.spi.IMessagesStore;\nimport io.moquette.spi.ISessionsStore;\nimport io.moquette.spi.IStore;\nimport io.moquette.spi.impl.security.PermitAllAuthorizator;\nimport io.moquette.spi.impl.security.TokenAuthenticator;\nimport io.moquette.spi.security.IAuthenticator;\nimport io.moquette.spi.security.IAuthorizator;\n\n/**\n * It's main responsibility is bootstrap the ProtocolProcessor.\n */\npublic class ProtocolProcessorBootstrapper {\n\n    private static final Logger LOG = LoggerFactory.getLogger(ProtocolProcessorBootstrapper.class);\n    public static final String INMEMDB_STORE_CLASS = \"io.moquette.persistence.MemoryStorageService\";\n\n    private ISessionsStore m_sessionsStore;\n\n    private Runnable storeShutdown;\n\n    private final ProtocolProcessor m_processor = new ProtocolProcessor();\n    private ConnectionDescriptorStore connectionDescriptors;\n\n    public ProtocolProcessorBootstrapper() {\n    }\n\n    /**\n     * Initialize the processing part of the broker.\n     *\n     * @param props\n     *            the properties carrier where some props like port end host could be loaded. For\n     *            the full list check of configurable properties check wildfirechat.conf file.\n     * @param embeddedObservers\n     *            a list of callbacks to be notified of certain events inside the broker. Could be\n     *            empty list of null.\n     * @param authenticator\n     *            an implementation of the authenticator to be used, if null load that specified in\n     *            config and fallback on the default one (permit all).\n     * @param authorizator\n     *            an implementation of the authorizator to be used, if null load that specified in\n     *            config and fallback on the default one (permit all).\n     * @param server\n     *            the server to init.\n     * @return the processor created for the broker.\n     */\n    public ProtocolProcessor init(IConfig props, List<? extends InterceptHandler> embeddedObservers,\n            IAuthenticator authenticator, IAuthorizator authorizator, Server server, IStore store) {\n        IMessagesStore messagesStore;\n        messagesStore = store.messagesStore();\n        m_sessionsStore = store.sessionsStore();\n        storeShutdown = new Runnable() {\n            @Override\n            public void run() {\n                store.close();\n            }\n        };\n\n        LOG.info(\"Configuring message interceptors...\");\n\n        List<InterceptHandler> observers = new ArrayList<>(embeddedObservers);\n        String interceptorClassName = props.getProperty(BrokerConstants.INTERCEPT_HANDLER_PROPERTY_NAME);\n        if (interceptorClassName != null && !interceptorClassName.isEmpty()) {\n            InterceptHandler handler = loadClass(interceptorClassName, InterceptHandler.class, Server.class, server);\n            if (handler != null) {\n                observers.add(handler);\n            }\n        }\n        BrokerInterceptor interceptor = new BrokerInterceptor(props, observers);\n\n        LOG.info(\"Configuring MQTT authenticator...\");\n        authenticator = new TokenAuthenticator();\n        \n\n        LOG.info(\"Configuring MQTT authorizator...\");\n        String authorizatorClassName = props.getProperty(BrokerConstants.AUTHORIZATOR_CLASS_NAME, \"\");\n        if (authorizator == null && !authorizatorClassName.isEmpty()) {\n            authorizator = loadClass(authorizatorClassName, IAuthorizator.class, IConfig.class, props);\n        }\n\n        if (authorizator == null) {\n            authorizator = new PermitAllAuthorizator();\n            LOG.info(\"An {} authorizator instance will be used\", authorizator.getClass().getName());\n        }\n\n        LOG.info(\"Initializing connection descriptor store...\");\n        connectionDescriptors = new ConnectionDescriptorStore(m_sessionsStore);\n\n        LOG.info(\"Initializing MQTT protocol processor...\");\n        m_processor.init(connectionDescriptors, messagesStore, m_sessionsStore, authenticator, authorizator, interceptor, server);\n        return m_processor;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private <T, U> T loadClass(String className, Class<T> intrface, Class<U> constructorArgClass, U props) {\n        T instance = null;\n        try {\n            // check if constructor with constructor arg class parameter\n            // exists\n            LOG.info(\"Invoking constructor with {} argument. ClassName={}, interfaceName={}\",\n                    constructorArgClass.getName(), className, intrface.getName());\n            instance = this.getClass().getClassLoader()\n                .loadClass(className)\n                .asSubclass(intrface)\n                .getConstructor(constructorArgClass)\n                .newInstance(props);\n        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException ex) {\n            LOG.warn(\"Unable to invoke constructor with {} argument. ClassName={}, interfaceName={}, cause={}, errorMessage={}\",\n                    constructorArgClass.getName(), className, intrface.getName(), ex.getCause(), ex.getMessage());\n            return null;\n        } catch (NoSuchMethodException | InvocationTargetException e) {\n            try {\n                LOG.info(\"Invoking default constructor. ClassName={}, interfaceName={}\",\n                        className, intrface.getName());\n                // fallback to default constructor\n                instance = this.getClass().getClassLoader()\n                    .loadClass(className)\n                    .asSubclass(intrface)\n                    .newInstance();\n            } catch (InstantiationException | IllegalAccessException | ClassNotFoundException ex) {\n                LOG.error(\"Unable to invoke default constructor. ClassName={}, interfaceName={}, cause={}, errorMessage={}\",\n                        className, intrface.getName(), ex.getCause(), ex.getMessage());\n                return null;\n            }\n        }\n\n        return instance;\n    }\n\n    public ISessionsStore getSessionsStore() {\n        return m_sessionsStore;\n    }\n\n    public void shutdown() {\n        if (storeShutdown != null)\n            storeShutdown.run();\n        if (m_processor != null)\n            m_processor.shutdown();\n//        if (m_interceptor != null)\n//            m_interceptor.stop();\n    }\n\n    public ConnectionDescriptorStore getConnectionDescriptors() {\n        return connectionDescriptors;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/Qos1PublishHandler.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl;\n\nimport static cn.wildfirechat.common.ErrorCode.*;\nimport static io.moquette.spi.impl.Utils.readBytesAndRewind;\nimport static io.netty.handler.codec.mqtt.MqttMessageIdVariableHeader.from;\nimport static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.*;\nimport java.util.zip.GZIPOutputStream;\n\nimport cn.hutool.core.util.ReflectUtil;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.server.ThreadPoolExecutorWrapper;\nimport com.google.gson.Gson;\nimport com.xiaoleilu.loServer.action.ClassUtil;\nimport cn.wildfirechat.pojos.OutputCheckUserOnline;\nimport io.moquette.persistence.ServerAPIHelper;\nimport io.moquette.imhandler.Handler;\nimport io.moquette.imhandler.IMHandler;\nimport io.moquette.persistence.MemorySessionStore;\nimport io.moquette.server.ConnectionDescriptor;\nimport io.moquette.server.Server;\nimport io.moquette.spi.impl.security.AES;\nimport io.netty.handler.codec.mqtt.MqttVersion;\nimport io.netty.util.ReferenceCountUtil;\nimport io.netty.util.internal.StringUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport io.moquette.server.ConnectionDescriptorStore;\nimport io.moquette.server.netty.NettyUtils;\nimport io.moquette.spi.IMessagesStore;\nimport io.moquette.spi.ISessionsStore;\nimport io.moquette.spi.impl.subscriptions.Topic;\nimport io.moquette.spi.security.IAuthorizator;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.Channel;\nimport io.netty.handler.codec.mqtt.MqttFixedHeader;\nimport io.netty.handler.codec.mqtt.MqttMessageType;\nimport io.netty.handler.codec.mqtt.MqttPublishMessage;\nimport cn.wildfirechat.common.ErrorCode;\nimport win.liyufan.im.GsonUtil;\nimport win.liyufan.im.IMTopic;\nimport win.liyufan.im.RateLimiter;\nimport win.liyufan.im.Utility;\nimport win.liyufan.im.extended.mqttmessage.ModifiedMqttPubAckMessage;\n\npublic class Qos1PublishHandler extends QosPublishHandler {\n    private static final Logger LOG = LoggerFactory.getLogger(Qos1PublishHandler.class);\n\n    private final IMessagesStore m_messagesStore;\n    private final ConnectionDescriptorStore connectionDescriptors;\n    private final MessagesPublisher publisher;\n    private final ISessionsStore m_sessionStore;\n    private final ThreadPoolExecutorWrapper m_imBusinessExecutor;\n\n    private HashMap<String, IMHandler> m_imHandlers = new HashMap<>();\n\n    public Qos1PublishHandler(IAuthorizator authorizator, IMessagesStore messagesStore, BrokerInterceptor interceptor,\n                              ConnectionDescriptorStore connectionDescriptors, MessagesPublisher messagesPublisher,\n                              ISessionsStore sessionStore, ThreadPoolExecutorWrapper executorService, Server server) {\n        super(authorizator);\n        this.m_messagesStore = messagesStore;\n        this.connectionDescriptors = connectionDescriptors;\n        this.publisher = messagesPublisher;\n        this.m_sessionStore = sessionStore;\n        this.m_imBusinessExecutor = executorService;\n        IMHandler.init(m_messagesStore, m_sessionStore, publisher, m_imBusinessExecutor, server);\n        registerAllAction();\n    }\n\n    private void registerAllAction() {\n        try {\n            for (Class cls:ClassUtil.getAllAssignedClass(IMHandler.class)) {\n                Handler annotation = (Handler)cls.getAnnotation(Handler.class);\n                if(annotation != null) {\n                    IMHandler handler = (IMHandler) ReflectUtil.newInstance(cls);\n                    m_imHandlers.put(annotation.value(), handler);\n                }\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        } catch (ClassNotFoundException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n    }\n\n    public void onApiMessage(String fromUser, String clientId, byte[] message, int requestId, String from, String request, ProtoConstants.RequestSourceType requestSourceType) {\n        if (request.equals(ServerAPIHelper.CHECK_USER_ONLINE_REQUEST)) {\n            checkUserOnlineHandler(message, ackPayload -> ServerAPIHelper.sendResponse(ERROR_CODE_SUCCESS.getCode(), ackPayload, from, requestId));\n        } else {\n            imHandler(clientId, fromUser, request, message, (errorCode, ackPayload) -> {\n                if (requestId > 0) {\n                    byte[] response = new byte[ackPayload.readableBytes()];\n                    ackPayload.readBytes(response);\n                    ReferenceCountUtil.release(ackPayload);\n                    ServerAPIHelper.sendResponse(errorCode.getCode(), response, from, requestId);\n                }\n            }, requestSourceType);\n        }\n    }\n\n    void checkUserOnlineHandler(byte[] payloadContent, RouteCallback callback) {\n        m_imBusinessExecutor.execute(() -> {\n            String userId = new String(payloadContent);\n\n            int status;\n            Collection<MemorySessionStore.Session> useSessions = m_sessionStore.sessionForUser(userId);\n            OutputCheckUserOnline out = new OutputCheckUserOnline();\n\n            for (MemorySessionStore.Session session : useSessions) {\n                if (session.getDeleted() > 0) {\n                    continue;\n                }\n\n                ConnectionDescriptor descriptor = connectionDescriptors.getConnection(session.getClientID());\n                if (descriptor == null) {\n                    status = 1;\n                } else {\n                    status = 0;\n                }\n\n                out.addSession(userId, session.getClientID(), session.getPlatform(), status, session.getLastActiveTime(), session.getAppName(), session.getIp());\n            }\n\n            callback.onRouteHandled(GsonUtil.gson.toJson(out).getBytes());\n        });\n    }\n\n\tvoid imHandler(String clientID, String fromUser, String topic, byte[] payloadContent, IMCallback callback, ProtoConstants.RequestSourceType requestSourceType) {\n        LOG.info(\"imHandler fromUser={}, topic={}\", fromUser, topic);\n        IMCallback wrapper = (errorcode, ackPayload) -> {\n            ackPayload.resetReaderIndex();\n            byte code = ackPayload.readByte();\n            if(ackPayload.readableBytes() > 0) {\n                byte[] data = new byte[ackPayload.readableBytes()];\n                ackPayload.getBytes(1, data);\n                try {\n                    //clientID 为空的是server api请求。客户端不允许clientID为空\n                    if (!StringUtil.isNullOrEmpty(clientID)) {\n                        //在route时，使用系统根密钥。当route成功后，用户都使用用户密钥\n                        if (topic.equals(IMTopic.GetTokenTopic)) {\n                            data = AES.AESEncrypt(data, \"\");\n                        } else {\n                            MemorySessionStore.Session session = m_sessionStore.getSession(clientID);\n                            if (session != null && session.getUsername().equals(fromUser)) {\n                                if (data.length > 7*1024 && session.getMqttVersion().protocolLevel() >= MqttVersion.MQTT_5.protocolLevel()) {\n                                    ByteArrayOutputStream out = new ByteArrayOutputStream();\n                                    GZIPOutputStream gzip = null;\n                                    try {\n                                        gzip = new GZIPOutputStream(out);\n                                        gzip.write(data);\n                                    } catch (Exception e) {\n                                        e.printStackTrace();\n                                        Utility.printExecption(LOG, e);\n                                    } finally {\n                                        if(gzip != null) {\n                                            gzip.close();\n                                        }\n                                    }\n                                    data = out.toByteArray();\n                                    code = (byte)ErrorCode.ERROR_CODE_SUCCESS_GZIPED.code;\n                                }\n\n                                data = AES.AESEncrypt(data, session.getSecret());\n                            }\n                        }\n                    }\n                    ackPayload.clear();\n                    ackPayload.resetWriterIndex();\n                    ackPayload.writeByte(code);\n                    ackPayload.writeBytes(data);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e);\n                }\n            }\n            ackPayload.resetReaderIndex();\n            try {\n                callback.onIMHandled(errorcode, ackPayload);\n            } catch (Exception e) {\n                e.printStackTrace();\n                Utility.printExecption(LOG, e);\n            }\n        };\n\n        IMHandler handler = m_imHandlers.get(topic);\n        if (handler != null) {\n            handler.doHandler(clientID, fromUser, topic, payloadContent, wrapper, requestSourceType);\n        } else {\n            LOG.error(\"imHandler unknown topic={}\", topic);\n            ByteBuf ackPayload = Unpooled.buffer();\n            ackPayload.ensureWritable(1).writeByte(ERROR_CODE_NOT_IMPLEMENT.getCode());\n            try {\n                wrapper.onIMHandled(ERROR_CODE_NOT_IMPLEMENT, ackPayload);\n            } catch (Exception e) {\n                e.printStackTrace();\n                Utility.printExecption(LOG, e);\n            }\n        }\n    }\n\n\n    public interface IMCallback {\n        void onIMHandled(ErrorCode errorCode, ByteBuf ackPayload);\n    }\n\n    interface RouteCallback {\n        void onRouteHandled(byte[] ackPayload);\n    }\n\n    void receivedPublishQos1(Channel channel, MqttPublishMessage msg) {\n        // verify if topic can be write\n        final Topic topic = new Topic(msg.variableHeader().topicName());\n        String clientID = NettyUtils.clientID(channel);\n        String username = NettyUtils.userName(channel);\n        if (!m_authorizator.canWrite(topic, username, clientID)) {\n            LOG.error(\"MQTT client is not authorized to publish on topic. CId={}, topic={}\", clientID, topic);\n            return;\n        }\n\n        final int messageID = msg.variableHeader().packetId();\n        String imtopic = topic.getTopic();\n        ByteBuf payload = msg.payload();\n        byte[] payloadContent = readBytesAndRewind(payload);\n        if(payloadContent.length > 0) {\n            MemorySessionStore.Session session = m_sessionStore.getSession(clientID);\n            payloadContent = AES.AESDecrypt(payloadContent, session.getSecret(), true);\n            if(payloadContent == null) {\n                ByteBuf ackPayload = Unpooled.buffer();\n                ackPayload.ensureWritable(1).writeByte(ERROR_CODE_INVALID_DATA.getCode());\n                sendPubAck(clientID, messageID, ackPayload, ERROR_CODE_INVALID_DATA);\n                return;\n            }\n        }\n\n        imHandler(clientID, username, imtopic, payloadContent, (errorCode, ackPayload) -> sendPubAck(clientID, messageID, ackPayload, errorCode), ProtoConstants.RequestSourceType.Request_From_User);\n    }\n\n    private void sendPubAck(String clientId, int messageID, ByteBuf payload, ErrorCode errorCode) {\n        LOG.trace(\"sendPubAck invoked\");\n        MqttFixedHeader fixedHeader = new MqttFixedHeader(MqttMessageType.PUBACK, false, AT_MOST_ONCE, false, 0);\n        ModifiedMqttPubAckMessage pubAckMessage = new ModifiedMqttPubAckMessage(fixedHeader, from(messageID), payload);\n\n        try {\n            if (connectionDescriptors == null) {\n                throw new RuntimeException(\"Internal bad error, found connectionDescriptors to null while it should \" +\n                    \"be initialized, somewhere it's overwritten!!\");\n            }\n            LOG.debug(\"clientIDs are {}\", connectionDescriptors);\n            if (!connectionDescriptors.isConnected(clientId)) {\n                throw new RuntimeException(String.format(\"Can't find a ConnectionDescriptor for client %s in cache %s\",\n                    clientId, connectionDescriptors));\n            }\n            connectionDescriptors.sendMessage(pubAckMessage, messageID, clientId, errorCode);\n        } catch (Throwable t) {\n            LOG.error(null, t);\n        }\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/QosPublishHandler.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport io.moquette.server.netty.NettyUtils;\nimport io.moquette.spi.impl.subscriptions.Topic;\nimport io.moquette.spi.security.IAuthorizator;\nimport io.netty.channel.Channel;\n\nabstract class QosPublishHandler {\n\n    private static final Logger LOG = LoggerFactory.getLogger(QosPublishHandler.class);\n\n    protected final IAuthorizator m_authorizator;\n\n    protected QosPublishHandler(IAuthorizator m_authorizator) {\n        this.m_authorizator = m_authorizator;\n    }\n\n    public boolean checkWriteOnTopic(Topic topic, Channel channel) {\n        String clientID = NettyUtils.clientID(channel);\n        String username = NettyUtils.userName(channel);\n        if (!m_authorizator.canWrite(topic, username, clientID)) {\n            LOG.error(\"MQTT client is not authorized to publish on topic. CId={}, topic={}\", clientID, topic);\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/Utils.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.handler.codec.mqtt.MqttMessage;\nimport io.netty.handler.codec.mqtt.MqttMessageIdVariableHeader;\nimport java.util.Map;\n\n/**\n * Utility static methods, like Map get with default value, or elvis operator.\n */\npublic final class Utils {\n\n    public static <T, K> T defaultGet(Map<K, T> map, K key, T defaultValue) {\n        T value = map.get(key);\n        if (value != null) {\n            return value;\n        }\n        return defaultValue;\n    }\n\n    public static int messageId(MqttMessage msg) {\n        return ((MqttMessageIdVariableHeader) msg.variableHeader()).messageId();\n    }\n\n    public static byte[] readBytesAndRewind(ByteBuf payload) {\n        byte[] payloadContent = new byte[payload.readableBytes()];\n        int mark = payload.readerIndex();\n        payload.readBytes(payloadContent);\n        payload.readerIndex(mark);\n        return payloadContent;\n    }\n\n    private Utils() {\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/security/ACLFileParser.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl.security;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport java.io.*;\nimport java.text.ParseException;\n\n/**\n * Parses the acl configuration file. If a line starts with # it's comment. Blank lines are skipped.\n * The format is \"topic [read|write|readwrite] {topic name}\"\n */\npublic final class ACLFileParser {\n\n    private static final Logger LOG = LoggerFactory.getLogger(ACLFileParser.class);\n\n    /**\n     * Parse the configuration from file.\n     *\n     * @param file\n     *            to parse\n     * @return the collector of authorizations form reader passed into.\n     * @throws ParseException\n     *             if the format is not compliant.\n     */\n    public static AuthorizationsCollector parse(File file) throws ParseException {\n        if (file == null) {\n            LOG.warn(\"parsing NULL file, so fallback on default configuration!\");\n            return AuthorizationsCollector.emptyImmutableCollector();\n        }\n        if (!file.exists()) {\n            LOG.warn(\n                    String.format(\n                            \"parsing not existing file %s, so fallback on default configuration!\",\n                            file.getAbsolutePath()));\n            return AuthorizationsCollector.emptyImmutableCollector();\n        }\n        try {\n            FileReader reader = new FileReader(file);\n            return parse(reader);\n        } catch (FileNotFoundException fex) {\n            LOG.warn(\n                    String.format(\n                            \"parsing not existing file %s, so fallback on default configuration!\",\n                            file.getAbsolutePath()),\n                    fex);\n            return AuthorizationsCollector.emptyImmutableCollector();\n        }\n    }\n\n    /**\n     * Parse the ACL configuration file\n     *\n     * @param reader\n     *            to parse\n     * @return the collector of authorizations form reader passed into.\n     * @throws ParseException\n     *             if the format is not compliant.\n     */\n    public static AuthorizationsCollector parse(Reader reader) throws ParseException {\n        if (reader == null) {\n            // just log and return default properties\n            LOG.warn(\"parsing NULL reader, so fallback on default configuration!\");\n            return AuthorizationsCollector.emptyImmutableCollector();\n        }\n\n        BufferedReader br = new BufferedReader(reader);\n        String line;\n        AuthorizationsCollector collector = new AuthorizationsCollector();\n\n        try {\n            while ((line = br.readLine()) != null) {\n                int commentMarker = line.indexOf('#');\n                if (commentMarker != -1) {\n                    if (commentMarker == 0) {\n                        // skip its a comment\n                        continue;\n                    } else {\n                        // it's a malformed comment\n                        throw new ParseException(line, commentMarker);\n                    }\n                } else {\n                    if (line.isEmpty() || line.matches(\"^\\\\s*$\")) {\n                        // skip it's a black line\n                        continue;\n                    }\n\n                    collector.parse(line);\n                }\n            }\n        } catch (IOException ex) {\n            throw new ParseException(\"Failed to read\", 1);\n        }\n        return collector;\n    }\n\n    private ACLFileParser() {\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/security/AES.java",
    "content": "package io.moquette.spi.impl.security;\n\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Arrays;\n\nimport javax.crypto.BadPaddingException;\nimport javax.crypto.Cipher;\nimport javax.crypto.IllegalBlockSizeException;\nimport javax.crypto.NoSuchPaddingException;\nimport javax.crypto.spec.IvParameterSpec;\nimport javax.crypto.spec.SecretKeySpec;\n\npublic class AES {\n    public static int keyLen = 16;\n    private final static int ivLen = 16;\n    private static byte[] aes_key= {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,0x3A,0x1F,0x28,0x39,0x4F,0x52,0x68,0x79,0x71,0x73,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F};\n\n    public static byte[] AESEncrypt(String sSrc, String userKey) {\n        return AESEncrypt(sSrc.getBytes(), userKey);\n    }\n\n    public static void useAes256(boolean aes256) {\n        if(aes256)\n            keyLen = 32;\n        else\n            keyLen = 16;\n    }\n\n    public static byte[] AESEncrypt(byte[] tobeencrypdata, byte[] aesKey) {\n        if (aesKey == null) {\n            System.out.print(\"Key为空null\");\n            return null;\n        }\n        // 判断Key是否为16位\n        if (aesKey.length < keyLen) {\n            System.out.print(\"Key长度不是16位\");\n            return null;\n        }\n        if(aesKey.length > keyLen) {\n            aesKey = Arrays.copyOfRange(aesKey, 0, keyLen);\n        }\n\n        byte[] ivKeys;\n        if(aesKey.length == ivLen) {\n            ivKeys = aesKey;\n        } else {\n            ivKeys = Arrays.copyOfRange(aesKey, 0, ivLen);\n        }\n\n        try {\n            SecretKeySpec skeySpec = new SecretKeySpec(aesKey, \"AES\");\n            Cipher cipher = Cipher.getInstance(\"AES/CBC/PKCS5Padding\");//\"算法/模式/补码方式\"\n            IvParameterSpec iv = new IvParameterSpec(ivKeys);//使用CBC模式，需要一个向量iv，可增加加密算法的强度\n            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);\n\n            //2018.1.1 0:0:0 以来的小时数\n            int curhour = (int) ((System.currentTimeMillis()/1000 - 1514736000)/3600);\n\n            byte[] tobeencrypdatawithtime = new byte[tobeencrypdata.length + 4];\n            byte byte0 = (byte)(curhour & 0xFF);\n            tobeencrypdatawithtime[0] = byte0;\n\n            byte byte1 = (byte)((curhour & 0xFF00) >> 8);\n            tobeencrypdatawithtime[1] = byte1;\n\n            byte byte2 = (byte)((curhour & 0xFF0000) >> 16);\n            tobeencrypdatawithtime[2] = byte2;\n\n            byte byte3 = (byte)((curhour & 0xFF) >> 24);\n            tobeencrypdatawithtime[3] = byte3;\n\n            System.arraycopy(tobeencrypdata, 0, tobeencrypdatawithtime, 4, tobeencrypdata.length);\n\n\n            byte[] encrypted = cipher.doFinal(tobeencrypdatawithtime);\n            return encrypted;\n        } catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        } catch (NoSuchPaddingException e) {\n            e.printStackTrace();\n        } catch (InvalidKeyException e) {\n            e.printStackTrace();\n        } catch (InvalidAlgorithmParameterException e) {\n            e.printStackTrace();\n        } catch (IllegalBlockSizeException e) {\n            e.printStackTrace();\n        } catch (BadPaddingException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n    public static byte[] AESEncrypt(byte[] tobeencrypdata, String userKey) {\n        byte[] aesKey = aes_key;\n        if (userKey != null && !userKey.isEmpty()) {\n            aesKey = convertUserKey(userKey);\n        }\n        return AESEncrypt(tobeencrypdata, aesKey);\n    }\n\n    public static int getUnsignedByte (byte data){      //将data字节型数据转换为0~255 (0xFF 即BYTE)。\n        return data&0x0FF ;\n    }\n\n    private static byte[] convertUserKey(String userKey) {\n        byte[] key = new byte[keyLen];\n        for (int i = 0; i < keyLen; i++) {\n            key[i] = (byte) (userKey.charAt(i) & 0xFF);\n        }\n        return key;\n    }\n\n    public static byte[] AESDecrypt(byte[] sSrc, String userKey, boolean checkTime) {\n        return AESDecrypt(sSrc, userKey, checkTime, null);\n    }\n\n    public static byte[] AESDecrypt(byte[] sSrc, String userKey, boolean checkTime, boolean[] invalidTime) {\n        byte[] aesKey = aes_key;\n        if (userKey != null && !userKey.isEmpty()) {\n            aesKey = convertUserKey(userKey);\n        }\n        return AESDecrypt(sSrc, aesKey, checkTime, invalidTime);\n    }\n\n    public static byte[] AESDecrypt(byte[] sSrc, byte[] aesKey, boolean checkTime, boolean[] invalidTime) {\n        try {\n\n            // 判断Key是否正确\n            if (aesKey == null) {\n                aesKey = aes_key;\n            }\n            // 判断Key是否为16位\n            if (aesKey.length < keyLen) {\n                System.out.print(\"Key长度不是16位\");\n                return null;\n            }\n\n            if(aesKey.length > keyLen) {\n                aesKey = Arrays.copyOfRange(aesKey, 0, keyLen);\n            }\n\n            byte[] ivKeys;\n            if(aesKey.length == ivLen) {\n                ivKeys = aesKey;\n            } else {\n                ivKeys = Arrays.copyOfRange(aesKey, 0, ivLen);\n            }\n\n            SecretKeySpec skeySpec = new SecretKeySpec(aesKey, \"AES\");\n            Cipher cipher = Cipher.getInstance(\"AES/CBC/PKCS5Padding\");\n            IvParameterSpec iv = new IvParameterSpec(ivKeys);\n            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);\n            try {\n                byte[] original = cipher.doFinal(sSrc);\n                int hours = 0;\n\n                if (original.length > 4) {\n                    hours += getUnsignedByte(original[3]);\n                    hours <<= 8;\n\n                    hours += getUnsignedByte(original[2]);\n                    hours <<= 8;\n\n                    hours += getUnsignedByte(original[1]);\n                    hours <<= 8;\n\n                    hours += getUnsignedByte(original[0]);\n\n                    //2018.1.1 0:0:0 以来的小时数\n                    int curhour = (int) ((System.currentTimeMillis()/1000 - 1514736000)/3600);\n\n                    if (Math.abs(curhour - hours)  > 24 && checkTime) {\n                        if(invalidTime != null) {\n                            invalidTime[0] = true;\n                        }\n                        return null;\n                    }\n                    byte[] neworiginal = new byte[original.length - 4];\n                    System.arraycopy(original, 4, neworiginal, 0, neworiginal.length);\n                    return neworiginal;\n                }\n                return null;\n            } catch (Exception e) {\n                System.out.println(e.toString());\n                return null;\n            }\n        } catch (Exception ex) {\n            System.out.println(ex.toString());\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/security/AcceptAllAuthenticator.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl.security;\n\nimport io.moquette.spi.security.IAuthenticator;\n\npublic class AcceptAllAuthenticator implements IAuthenticator {\n\n    public boolean checkValid(String clientId, String username, byte[] password) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/security/Authorization.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl.security;\n\nimport static io.moquette.spi.impl.security.Authorization.Permission.READWRITE;\nimport io.moquette.spi.impl.subscriptions.Topic;\n\n/**\n * Carries the read/write authorization to topics for the users.\n */\npublic class Authorization {\n\n    protected final Topic topic;\n    protected final Permission permission;\n\n    /**\n     * Access rights\n     */\n    enum Permission {\n        READ, WRITE, READWRITE\n    }\n\n    Authorization(Topic topic) {\n        this(topic, Permission.READWRITE);\n    }\n\n    Authorization(Topic topic, Permission permission) {\n        this.topic = topic;\n        this.permission = permission;\n    }\n\n    public boolean grant(Permission desiredPermission) {\n        return permission == desiredPermission || permission == READWRITE;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o)\n            return true;\n        if (o == null || getClass() != o.getClass())\n            return false;\n\n        Authorization that = (Authorization) o;\n\n        if (permission != that.permission)\n            return false;\n        if (!topic.equals(that.topic))\n            return false;\n\n        return true;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = topic.hashCode();\n        result = 31 * result + permission.hashCode();\n        return result;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/security/AuthorizationsCollector.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl.security;\n\nimport io.moquette.spi.impl.subscriptions.Topic;\nimport io.moquette.spi.security.IAuthorizator;\nimport java.text.ParseException;\nimport java.util.*;\n\n/**\n * Used by the ACLFileParser to push all authorizations it finds. ACLAuthorizator uses it in read\n * mode to check it topics matches the ACLs.\n *\n * Not thread safe.\n */\nclass AuthorizationsCollector implements IAuthorizator {\n\n    private List<Authorization> m_globalAuthorizations = new ArrayList<>();\n    private List<Authorization> m_patternAuthorizations = new ArrayList<>();\n    private Map<String, List<Authorization>> m_userAuthorizations = new HashMap<>();\n    private boolean m_parsingUsersSpecificSection;\n    private boolean m_parsingPatternSpecificSection;\n    private String m_currentUser = \"\";\n\n    static final AuthorizationsCollector emptyImmutableCollector() {\n        AuthorizationsCollector coll = new AuthorizationsCollector();\n        coll.m_globalAuthorizations = Collections.emptyList();\n        coll.m_patternAuthorizations = Collections.emptyList();\n        coll.m_userAuthorizations = Collections.emptyMap();\n        return coll;\n    }\n\n    void parse(String line) throws ParseException {\n        Authorization acl = parseAuthLine(line);\n        if (acl == null) {\n            // skip it's a user\n            return;\n        }\n        if (m_parsingUsersSpecificSection) {\n            // TODO in java 8 switch to m_userAuthorizations.putIfAbsent(m_currentUser, new\n            // ArrayList());\n            if (!m_userAuthorizations.containsKey(m_currentUser)) {\n                m_userAuthorizations.put(m_currentUser, new ArrayList<Authorization>());\n            }\n            List<Authorization> userAuths = m_userAuthorizations.get(m_currentUser);\n            userAuths.add(acl);\n        } else if (m_parsingPatternSpecificSection) {\n            m_patternAuthorizations.add(acl);\n        } else {\n            m_globalAuthorizations.add(acl);\n        }\n    }\n\n    protected Authorization parseAuthLine(String line) throws ParseException {\n        String[] tokens = line.split(\"\\\\s+\");\n        String keyword = tokens[0].toLowerCase();\n        switch (keyword) {\n            case \"topic\":\n                return createAuthorization(line, tokens);\n            case \"user\":\n                m_parsingUsersSpecificSection = true;\n                m_currentUser = tokens[1];\n                m_parsingPatternSpecificSection = false;\n                return null;\n            case \"pattern\":\n                m_parsingUsersSpecificSection = false;\n                m_currentUser = \"\";\n                m_parsingPatternSpecificSection = true;\n                return createAuthorization(line, tokens);\n            default:\n                throw new ParseException(String.format(\"invalid line definition found %s\", line), 1);\n        }\n    }\n\n    private Authorization createAuthorization(String line, String[] tokens) throws ParseException {\n        if (tokens.length > 2) {\n            // if the tokenized lines has 3 token the second must be the permission\n            try {\n                Authorization.Permission permission = Authorization.Permission.valueOf(tokens[1].toUpperCase());\n                // bring topic with all original spacing\n                Topic topic = new Topic(line.substring(line.indexOf(tokens[2])));\n\n                return new Authorization(topic, permission);\n            } catch (IllegalArgumentException iaex) {\n                throw new ParseException(\"invalid permission token\", 1);\n            }\n        }\n        Topic topic = new Topic(tokens[1]);\n        return new Authorization(topic);\n    }\n\n    @Override\n    public boolean canWrite(Topic topic, String user, String client) {\n        return canDoOperation(topic, Authorization.Permission.WRITE, user, client);\n    }\n\n    @Override\n    public boolean canRead(Topic topic, String user, String client) {\n        return canDoOperation(topic, Authorization.Permission.READ, user, client);\n    }\n\n    private boolean canDoOperation(Topic topic, Authorization.Permission permission, String username, String client) {\n        if (matchACL(m_globalAuthorizations, topic, permission)) {\n            return true;\n        }\n\n        if (isNotEmpty(client) || isNotEmpty(username)) {\n            for (Authorization auth : m_patternAuthorizations) {\n                Topic substitutedTopic = new Topic(auth.topic.toString().replace(\"%c\", client).replace(\"%u\", username));\n                if (auth.grant(permission)) {\n                    if (topic.match(substitutedTopic)) {\n                        return true;\n                    }\n                }\n            }\n        }\n\n        if (isNotEmpty(username)) {\n            if (m_userAuthorizations.containsKey(username)) {\n                List<Authorization> auths = m_userAuthorizations.get(username);\n                if (matchACL(auths, topic, permission)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    private boolean matchACL(List<Authorization> auths, Topic topic, Authorization.Permission permission) {\n        for (Authorization auth : auths) {\n            if (auth.grant(permission)) {\n                if (topic.match(auth.topic)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    private boolean isNotEmpty(String client) {\n        return client != null && !client.isEmpty();\n    }\n\n    public boolean isEmpty() {\n        return m_globalAuthorizations.isEmpty();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/security/DBAuthenticator.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl.security;\n\nimport io.moquette.BrokerConstants;\nimport io.moquette.server.config.IConfig;\nimport io.moquette.spi.security.IAuthenticator;\nimport org.apache.commons.codec.binary.Hex;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport win.liyufan.im.Utility;\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.sql.*;\n\n/**\n * Load user credentials from a SQL database. sql driver must be provided at runtime\n */\npublic class DBAuthenticator implements IAuthenticator {\n\n    private static final Logger LOG = LoggerFactory.getLogger(DBAuthenticator.class);\n\n    private final MessageDigest messageDigest;\n    private final PreparedStatement preparedStatement;\n\n    public DBAuthenticator(IConfig conf) {\n        this(\n                conf.getProperty(BrokerConstants.DB_AUTHENTICATOR_DRIVER, \"\"),\n                conf.getProperty(BrokerConstants.DB_AUTHENTICATOR_URL, \"\"),\n                conf.getProperty(BrokerConstants.DB_AUTHENTICATOR_QUERY, \"\"),\n                conf.getProperty(BrokerConstants.DB_AUTHENTICATOR_DIGEST, \"\"));\n    }\n\n    /**\n     * provide authenticator from SQL database\n     *\n     * @param driver\n     *            : jdbc driver class like : \"org.postgresql.Driver\"\n     * @param jdbcUrl\n     *            : jdbc url like : \"jdbc:postgresql://host:port/dbname\"\n     * @param sqlQuery\n     *            : sql query like : \"SELECT PASSWORD FROM USER WHERE LOGIN=?\"\n     * @param digestMethod\n     *            : password encoding algorithm : \"MD5\", \"SHA-1\", \"SHA-256\"\n     */\n    public DBAuthenticator(String driver, String jdbcUrl, String sqlQuery, String digestMethod) {\n\n        try {\n            Class.forName(driver);\n            final Connection connection = DriverManager.getConnection(jdbcUrl);\n            this.messageDigest = MessageDigest.getInstance(digestMethod);\n            this.preparedStatement = connection.prepareStatement(sqlQuery);\n        } catch (ClassNotFoundException cnfe) {\n            LOG.error(String.format(\"Can't find driver %s\", driver), cnfe);\n            throw new RuntimeException(cnfe);\n        } catch (SQLException sqle) {\n            LOG.error(String.format(\"Can't connect to %s\", jdbcUrl), sqle);\n            throw new RuntimeException(sqle);\n        } catch (NoSuchAlgorithmException nsaex) {\n            LOG.error(String.format(\"Can't find %s for password encoding\", digestMethod), nsaex);\n            throw new RuntimeException(nsaex);\n        }\n    }\n\n    @Override\n    public synchronized boolean checkValid(String clientId, String username, byte[] password) {\n        // Check Username / Password in DB using sqlQuery\n        if (username == null || password == null) {\n            LOG.info(\"username or password was null\");\n            return false;\n        }\n        ResultSet r = null;\n        try {\n            this.preparedStatement.setString(1, username);\n            r = this.preparedStatement.executeQuery();\n            if (r.next()) {\n                final String foundPwq = r.getString(1);\n                messageDigest.update(password);\n                byte[] digest = messageDigest.digest();\n                String encodedPasswd = new String(Hex.encodeHex(digest));\n                return foundPwq.equals(encodedPasswd);\n            }\n            r.close();\n        } catch (SQLException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n        return false;\n    }\n\n    @Override\n    protected void finalize() throws Throwable {\n        this.preparedStatement.close();\n        this.preparedStatement.getConnection().close();\n        super.finalize();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/security/DenyAllAuthorizator.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl.security;\n\nimport io.moquette.spi.impl.subscriptions.Topic;\nimport io.moquette.spi.security.IAuthorizator;\n\npublic class DenyAllAuthorizator implements IAuthorizator {\n\n    @Override\n    public boolean canWrite(Topic topic, String user, String client) {\n        return true;\n    }\n\n    @Override\n    public boolean canRead(Topic topic, String user, String client) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/security/FileAuthenticator.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl.security;\n\nimport io.moquette.server.config.FileResourceLoader;\n\n/**\n * Load user credentials from a text file. Each line of the file is formatted as\n * \"[username]:[sha256(password)]\". The username mustn't contains : char.\n *\n * To encode your password from command line on Linux systems, you could use:\n *\n * <pre>\n *     echo -n \"yourpassword\" | sha256sum\n * </pre>\n *\n * NB -n is important because echo append a newline by default at the of string. -n avoid this\n * behaviour.\n *\n * @deprecated user {@link ResourceAuthenticator} instead\n */\npublic class FileAuthenticator extends ResourceAuthenticator {\n\n    public FileAuthenticator(String parent, String filePath) {\n        super(new FileResourceLoader(parent), filePath);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/security/ITokenGenerator.java",
    "content": "package io.moquette.spi.impl.security;\n\npublic interface ITokenGenerator {\n\tpublic String generateToken(String username);\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/security/PermitAllAuthorizator.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl.security;\n\nimport io.moquette.spi.impl.subscriptions.Topic;\nimport io.moquette.spi.security.IAuthorizator;\n\npublic class PermitAllAuthorizator implements IAuthorizator {\n\n    @Override\n    public boolean canWrite(Topic topic, String user, String client) {\n        return true;\n    }\n\n    @Override\n    public boolean canRead(Topic topic, String user, String client) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/security/ResourceAuthenticator.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl.security;\n\nimport io.moquette.server.config.IResourceLoader;\nimport io.moquette.spi.security.IAuthenticator;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.Reader;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.text.ParseException;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Load user credentials from a text resource. Each line of the file is formatted as\n * \"[username]:[sha256(password)]\". The username mustn't contains : char.\n *\n * To encode your password from command line on Linux systems, you could use:\n *\n * <pre>\n *     echo -n \"yourpassword\" | sha256sum\n * </pre>\n *\n * NB -n is important because echo append a newline by default at the of string. -n avoid this\n * behaviour.\n */\npublic class ResourceAuthenticator implements IAuthenticator {\n\n    protected static final Logger LOG = LoggerFactory.getLogger(ResourceAuthenticator.class);\n\n    private Map<String, String> m_identities = new HashMap<>();\n\n    public ResourceAuthenticator(IResourceLoader resourceLoader, String resourceName) {\n        try {\n            MessageDigest.getInstance(\"SHA-256\");\n        } catch (NoSuchAlgorithmException nsaex) {\n            LOG.error(\"Can't find SHA-256 for password encoding\", nsaex);\n            throw new RuntimeException(nsaex);\n        }\n\n        LOG.info(String.format(\"Loading password %s %s\", resourceLoader.getName(), resourceName));\n        Reader reader = null;\n        try {\n            reader = resourceLoader.loadResource(resourceName);\n            if (reader == null) {\n                LOG.warn(String.format(\"Parsing not existing %s %s\", resourceLoader.getName(), resourceName));\n            } else {\n                parse(reader);\n            }\n        } catch (IResourceLoader.ResourceIsDirectoryException e) {\n            LOG.warn(String.format(\"Trying to parse directory %s\", resourceName));\n        } catch (ParseException pex) {\n            LOG.warn(\n                    String.format(\"Format error in parsing password %s %s\", resourceLoader.getName(), resourceName),\n                    pex);\n        }\n    }\n\n    private void parse(Reader reader) throws ParseException {\n        if (reader == null) {\n            return;\n        }\n\n        BufferedReader br = new BufferedReader(reader);\n        String line;\n        try {\n            while ((line = br.readLine()) != null) {\n                int commentMarker = line.indexOf('#');\n                if (commentMarker != -1) {\n                    if (commentMarker == 0) {\n                        // skip its a comment\n                        continue;\n                    } else {\n                        // it's a malformed comment\n                        throw new ParseException(line, commentMarker);\n                    }\n                } else {\n                    if (line.isEmpty() || line.matches(\"^\\\\s*$\")) {\n                        // skip it's a black line\n                        continue;\n                    }\n\n                    // split till the first space\n                    int delimiterIdx = line.indexOf(':');\n                    String username = line.substring(0, delimiterIdx).trim();\n                    String password = line.substring(delimiterIdx + 1).trim();\n\n                    m_identities.put(username, password);\n                }\n            }\n        } catch (IOException ex) {\n            throw new ParseException(\"Failed to read\", 1);\n        }\n    }\n\n    @Override\n    public boolean checkValid(String clientId, String username, byte[] password) {\n        if (username == null || password == null) {\n            LOG.info(\"username or password was null\");\n            return false;\n        }\n        String foundPwq = m_identities.get(username);\n        if (foundPwq == null) {\n            return false;\n        }\n        String encodedPasswd = DigestUtils.sha256Hex(password);\n        return foundPwq.equals(encodedPasswd);\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/security/TokenAuthenticator.java",
    "content": "package io.moquette.spi.impl.security;\n\nimport java.io.IOException;\n\nimport io.moquette.spi.security.IAuthenticator;\nimport io.moquette.spi.security.Tokenor;\n\npublic class TokenAuthenticator implements IAuthenticator, ITokenGenerator {\n    public static void main(String[] args) throws IOException {\n    \tTokenAuthenticator authenticator = new TokenAuthenticator();\n    \tString strToken = authenticator.generateToken(\"user1\");\n    \tif (authenticator.checkValid(null, \"user1\", strToken.getBytes())) {\n\t\t\tSystem.out.println(\"pass\" + strToken);\n\t\t} else {\n\t\t\tSystem.out.println(\"fail\" + strToken);\n\t\t}\n    }\n\n\n\t@Override\n\tpublic boolean checkValid(String clientId, String username, byte[] password) {\n        String id = Tokenor.getUserId(password);\n        if (id != null && id.equals(username)) {\n            return true;\n        }\n\t\treturn false;\n\t}\n\n\t@Override\n\tpublic String generateToken(String username) {\n\t\treturn Tokenor.getToken(username);\n\t}\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/subscriptions/Token.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl.subscriptions;\n\n/**\n * Internal use only class.\n */\npublic class Token {\n\n    static final Token EMPTY = new Token(\"\");\n    static final Token MULTI = new Token(\"#\");\n    static final Token SINGLE = new Token(\"+\");\n    final String name;\n\n    protected Token(String s) {\n        name = s;\n    }\n\n    protected String name() {\n        return name;\n    }\n\n    protected boolean match(Token t) {\n        if (t == MULTI || t == SINGLE) {\n            return false;\n        }\n\n        if (this == MULTI || this == SINGLE) {\n            return true;\n        }\n\n        return equals(t);\n    }\n\n    @Override\n    public int hashCode() {\n        int hash = 7;\n        hash = 29 * hash + (this.name != null ? this.name.hashCode() : 0);\n        return hash;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        final Token other = (Token) obj;\n        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public String toString() {\n        return name;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/impl/subscriptions/Topic.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.impl.subscriptions;\n\nimport java.io.Serializable;\nimport java.text.ParseException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class Topic implements Serializable {\n\n    private static final Logger LOG = LoggerFactory.getLogger(Topic.class);\n\n    private static final long serialVersionUID = 2438799283749822L;\n\n    private final String topic;\n\n    private transient List<Token> tokens;\n\n    private transient boolean valid;\n\n    public Topic(String topic) {\n        this.topic = topic;\n    }\n\n    \n    public String getTopic() {\n\t\treturn topic;\n\t}\n\n\n\tpublic List<Token> getTokens() {\n        if (tokens == null) {\n            try {\n                tokens = parseTopic(topic);\n                valid = true;\n            } catch (ParseException e) {\n                valid = false;\n                LOG.error(\"Error parsing the topic: {}, message: {}\", topic, e.getMessage());\n            }\n        }\n\n        return tokens;\n    }\n\n    private List<Token> parseTopic(String topic) throws ParseException {\n        List<Token> res = new ArrayList<>();\n        String[] splitted = topic.split(\"/\");\n\n        if (splitted.length == 0) {\n            res.add(Token.EMPTY);\n        }\n\n        if (topic.endsWith(\"/\")) {\n            // Add a fictious space\n            String[] newSplitted = new String[splitted.length + 1];\n            System.arraycopy(splitted, 0, newSplitted, 0, splitted.length);\n            newSplitted[splitted.length] = \"\";\n            splitted = newSplitted;\n        }\n\n        for (int i = 0; i < splitted.length; i++) {\n            String s = splitted[i];\n            if (s.isEmpty()) {\n                // if (i != 0) {\n                // throw new ParseException(\"Bad format of topic, expetec topic name between\n                // separators\", i);\n                // }\n                res.add(Token.EMPTY);\n            } else if (s.equals(\"#\")) {\n                // check that multi is the last symbol\n                if (i != splitted.length - 1) {\n                    throw new ParseException(\n                            \"Bad format of topic, the multi symbol (#) has to be the last one after a separator\",\n                            i);\n                }\n                res.add(Token.MULTI);\n            } else if (s.contains(\"#\")) {\n                throw new ParseException(\"Bad format of topic, invalid subtopic name: \" + s, i);\n            } else if (s.equals(\"+\")) {\n                res.add(Token.SINGLE);\n            } else if (s.contains(\"+\")) {\n                throw new ParseException(\"Bad format of topic, invalid subtopic name: \" + s, i);\n            } else {\n                res.add(new Token(s));\n            }\n        }\n\n        return res;\n    }\n\n    public boolean isValid() {\n        if (tokens == null)\n            getTokens();\n\n        return valid;\n    }\n\n    /**\n     * Verify if the 2 topics matching respecting the rules of MQTT Appendix A\n     *\n     * @param subscriptionTopic\n     *            the topic filter of the subscription\n     * @return true if the two topics match.\n     */\n    // TODO reimplement with iterators or with queues\n    public boolean match(Topic subscriptionTopic) {\n        List<Token> msgTokens = getTokens();\n        List<Token> subscriptionTokens = subscriptionTopic.getTokens();\n        int i = 0;\n        for (; i < subscriptionTokens.size(); i++) {\n            Token subToken = subscriptionTokens.get(i);\n            if (subToken != Token.MULTI && subToken != Token.SINGLE) {\n                if (i >= msgTokens.size()) {\n                    return false;\n                }\n                Token msgToken = msgTokens.get(i);\n                if (!msgToken.equals(subToken)) {\n                    return false;\n                }\n            } else {\n                if (subToken == Token.MULTI) {\n                    return true;\n                }\n                if (subToken == Token.SINGLE) {\n                    // skip a step forward\n                }\n            }\n        }\n        // if last token was a SINGLE then treat it as an empty\n        // if (subToken == Token.SINGLE && (i - msgTokens.size() == 1)) {\n        // i--;\n        // }\n        return i == msgTokens.size();\n    }\n\n    @Override\n    public String toString() {\n        return topic;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (obj == null) {\n            return false;\n        }\n        if (getClass() != obj.getClass()) {\n            return false;\n        }\n        Topic other = (Topic) obj;\n\n        return Objects.equals(this.topic, other.topic);\n    }\n\n    @Override\n    public int hashCode() {\n        return topic.hashCode();\n    }\n\n    /**\n     * Factory method\n     * */\n    public static Topic asTopic(String s) {\n        return new Topic(s);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/security/DES.java",
    "content": "package io.moquette.spi.security;\n\nimport javax.crypto.*;\nimport javax.crypto.spec.DESKeySpec;\nimport javax.crypto.spec.IvParameterSpec;\nimport javax.crypto.spec.SecretKeySpec;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\nimport java.security.spec.InvalidKeySpecException;\nimport java.util.Base64;\n\npublic class DES {\n\tprivate static final String Encrypt_Password = \"abcdefgh\";\n    private static byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 };\n\n    private static byte[] aes_key= {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F};\n    public static String decryptDES(String decryptString) throws Exception {\n        byte[] byteMi = Base64.getDecoder().decode(decryptString);\n        IvParameterSpec zeroIv = new IvParameterSpec(iv);\n        SecretKeySpec key = new SecretKeySpec(Encrypt_Password.getBytes(), \"DES\");\n        Cipher cipher = Cipher.getInstance(\"DES/CBC/PKCS5Padding\");\n        cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);\n        byte decryptedData[] = cipher.doFinal(byteMi);\n\n        return new String(decryptedData);\n    }\n    public static void init(byte[] secret) {\n        if (secret != null && secret.length == 16) {\n            aes_key = new byte[16];\n            for (int i = 0; i < 16; i++) {\n                aes_key[i] = secret[i];\n            }\n        } else {\n            System.out.println(\"Error int key error, secret incorrect\");\n        }\n    }\n    public static String encryptDES(String encryptString) throws Exception {\n        IvParameterSpec zeroIv = new IvParameterSpec(iv);\n        SecretKeySpec key = new SecretKeySpec(Encrypt_Password.getBytes(), \"DES\");\n        Cipher cipher = Cipher.getInstance(\"DES/CBC/PKCS5Padding\");\n        cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);\n        byte[] encryptedData = cipher.doFinal(encryptString.getBytes());\n        return new String(Base64.getEncoder().encode(encryptedData));\n    }\n\n\tpublic static byte[] encrypt(byte[] datasource) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {\n\t\tSecureRandom random = new SecureRandom();\n\t\tDESKeySpec desKey = new DESKeySpec(Encrypt_Password.getBytes());\n\t\t// 创建一个密匙工厂，然后用它把DESKeySpec转换成\n\t\tSecretKeyFactory keyFactory = SecretKeyFactory.getInstance(\"DES\");\n\t\tSecretKey securekey = keyFactory.generateSecret(desKey);\n\t\t// Cipher对象实际完成加密操作\n\t\tCipher cipher = Cipher.getInstance(\"DES\");\n\t\t// 用密匙初始化Cipher对象\n\t\tcipher.init(Cipher.ENCRYPT_MODE, securekey, random);\n\t\t// 现在，获取数据并加密\n\t\t// 正式执行加密操作\n\t\treturn cipher.doFinal(datasource);\n\t}\n\n\t/**\n\t * 解密\n\t * \n\t * @param src\n\t *            byte[]\n\t *            String\n\t * @return byte[]\n\t * @throws Exception\n\t */\n\tpublic static byte[] decrypt(byte[] src) throws Exception {\n\t\t// DES算法要求有一个可信任的随机数源\n\t\tSecureRandom random = new SecureRandom();\n\t\t// 创建一个DESKeySpec对象\n\t\tDESKeySpec desKey = new DESKeySpec(Encrypt_Password.getBytes());\n\t\t// 创建一个密匙工厂\n\t\tSecretKeyFactory keyFactory = SecretKeyFactory.getInstance(\"DES\");\n\t\t// 将DESKeySpec对象转换成SecretKey对象\n\t\tSecretKey securekey = keyFactory.generateSecret(desKey);\n\t\t// Cipher对象实际完成解密操作\n\t\tCipher cipher = Cipher.getInstance(\"DES\");\n\t\t// 用密匙初始化Cipher对象\n\t\tcipher.init(Cipher.DECRYPT_MODE, securekey, random);\n\t\t// 真正开始解密操作\n\t\treturn cipher.doFinal(src);\n\t}\n    public static byte[] AESEncrypt(String sSrc, String userKey) {\n        return AESEncrypt(sSrc.getBytes(), userKey);\n    }\n\n    public static byte[] AESEncrypt(byte[] tobeencrypdata, byte[] aesKey) {\n        if (aesKey == null) {\n            System.out.print(\"Key为空null\");\n            return null;\n        }\n        // 判断Key是否为16位\n        if (aesKey.length != 16) {\n            System.out.print(\"Key长度不是16位\");\n            return null;\n        }\n\n\n        try {\n            SecretKeySpec skeySpec = new SecretKeySpec(aesKey, \"AES\");\n            Cipher cipher = Cipher.getInstance(\"AES/CBC/PKCS5Padding\");//\"算法/模式/补码方式\"\n            IvParameterSpec iv = new IvParameterSpec(aesKey);//使用CBC模式，需要一个向量iv，可增加加密算法的强度\n            cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);\n\n            //2018.1.1 0:0:0 以来的小时数\n            int curhour = (int) ((System.currentTimeMillis()/1000 - 1514736000)/3600);\n\n            byte[] tobeencrypdatawithtime = new byte[tobeencrypdata.length + 4];\n            byte byte0 = (byte)(curhour & 0xFF);\n            tobeencrypdatawithtime[0] = byte0;\n\n            byte byte1 = (byte)((curhour & 0xFF00) >> 8);\n            tobeencrypdatawithtime[1] = byte1;\n\n            byte byte2 = (byte)((curhour & 0xFF0000) >> 16);\n            tobeencrypdatawithtime[2] = byte2;\n\n            byte byte3 = (byte)((curhour & 0xFF) >> 24);\n            tobeencrypdatawithtime[3] = byte3;\n\n            System.arraycopy(tobeencrypdata, 0, tobeencrypdatawithtime, 4, tobeencrypdata.length);\n\n\n            byte[] encrypted = cipher.doFinal(tobeencrypdatawithtime);\n            return encrypted;\n        } catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        } catch (NoSuchPaddingException e) {\n            e.printStackTrace();\n        } catch (InvalidKeyException e) {\n            e.printStackTrace();\n        } catch (InvalidAlgorithmParameterException e) {\n            e.printStackTrace();\n        } catch (IllegalBlockSizeException e) {\n            e.printStackTrace();\n        } catch (BadPaddingException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n    public static byte[] AESEncrypt(byte[] tobeencrypdata, String userKey) {\n        byte[] aesKey = aes_key;\n        if (userKey != null && !userKey.isEmpty()) {\n            aesKey = convertUserKey(userKey);\n        }\n        return AESEncrypt(tobeencrypdata, aesKey);\n    }\n\n    public static int getUnsignedByte (byte data){      //将data字节型数据转换为0~255 (0xFF 即BYTE)。\n        return data&0x0FF ;\n    }\n\n    private static byte[] convertUserKey(String userKey) {\n        byte[] key = new byte[16];\n        for (int i = 0; i < 16; i++) {\n            key[i] = (byte) (userKey.charAt(i) & 0xFF);\n        }\n        return key;\n    }\n\n    public static byte[] AESDecrypt(byte[] sSrc, String userKey, boolean checkTime) {\n        try {\n\n            byte[] aesKey = aes_key;\n            if (userKey != null && !userKey.isEmpty()) {\n                aesKey = convertUserKey(userKey);\n            }\n            // 判断Key是否正确\n            if (aesKey == null) {\n                System.out.print(\"Key为空null\");\n                return null;\n            }\n            // 判断Key是否为16位\n            if (aesKey.length != 16) {\n                System.out.print(\"Key长度不是16位\");\n                return null;\n            }\n\n            SecretKeySpec skeySpec = new SecretKeySpec(aesKey, \"AES\");\n            Cipher cipher = Cipher.getInstance(\"AES/CBC/PKCS5Padding\");\n            IvParameterSpec iv = new IvParameterSpec(aesKey);\n            cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);\n            try {\n                byte[] original = cipher.doFinal(sSrc);\n                int hours = 0;\n\n                if (original.length > 4) {\n                    hours += getUnsignedByte(original[3]);\n                    hours <<= 8;\n\n                    hours += getUnsignedByte(original[2]);\n                    hours <<= 8;\n\n                    hours += getUnsignedByte(original[1]);\n                    hours <<= 8;\n\n                    hours += getUnsignedByte(original[0]);\n\n                    //2018.1.1 0:0:0 以来的小时数\n                    int curhour = (int) ((System.currentTimeMillis()/1000 - 1514736000)/3600);\n\n                    if (curhour - hours > 24 && checkTime) {\n                        return null;\n                    }\n                    byte[] neworiginal = new byte[original.length - 4];\n                    System.arraycopy(original, 4, neworiginal, 0, neworiginal.length);\n                    return neworiginal;\n                }\n                return null;\n            } catch (Exception e) {\n                System.out.println(e.toString());\n                return null;\n            }\n        } catch (Exception ex) {\n            System.out.println(ex.toString());\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/security/IAuthenticator.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.security;\n\n/**\n * username and password checker\n */\npublic interface IAuthenticator {\n\n    boolean checkValid(String clientId, String username, byte[] password);\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/security/IAuthorizator.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.security;\n\nimport io.moquette.spi.impl.subscriptions.Topic;\n\n/**\n * ACL checker.\n *\n * Create an authorizator that matches topic names with same grammar of subscriptions. The # is\n * always a terminator and its the multilevel matcher. The + sign is the single level matcher.\n */\npublic interface IAuthorizator {\n\n    /**\n     * Ask the implementation of the authorizator if the topic can be used in a publish.\n     *\n     * @param topic\n     *            the topic to write to.\n     * @param user\n     *            the user\n     * @param client\n     *            the client\n     * @return true if the user from client can publish data on topic.\n     */\n    boolean canWrite(Topic topic, String user, String client);\n\n    boolean canRead(Topic topic, String user, String client);\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/security/ISslContextCreator.java",
    "content": "/*\n * Copyright (c) 2012-2017 The original author or authors\n * ------------------------------------------------------\n * All rights reserved. This program and the accompanying materials\n * are made available under the terms of the Eclipse Public License v1.0\n * and Apache License v2.0 which accompanies this distribution.\n *\n * The Eclipse Public License is available at\n * http://www.eclipse.org/legal/epl-v10.html\n *\n * The Apache License v2.0 is available at\n * http://www.opensource.org/licenses/apache2.0.php\n *\n * You may elect to redistribute this code under either of these licenses.\n */\n\npackage io.moquette.spi.security;\n\nimport javax.net.ssl.SSLContext;\n\n/**\n * SSL certificate loader used to open SSL connections (websocket and MQTT-S).\n */\npublic interface ISslContextCreator {\n\n    SSLContext initSSLContext();\n}\n"
  },
  {
    "path": "broker/src/main/java/io/moquette/spi/security/Tokenor.java",
    "content": "package io.moquette.spi.security;\n\n\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.spi.impl.security.AES;\n\npublic class Tokenor {\n\tprivate static String KEY = \"testim\";\n\tprivate static long expiredTime = Long.MAX_VALUE;\n\n\tpublic static void setKey(String key) {\n\t    if (!StringUtil.isNullOrEmpty(key)) {\n            KEY = key;\n        }\n    }\n\n    public static void setExpiredTime(long expiredTime) {\n        Tokenor.expiredTime = expiredTime;\n    }\n\n    public static String getUserId(byte[] password) {\n        try {\n            String signKey =\n                DES.decryptDES(new String(password));\n\n            if (signKey.startsWith(KEY + \"|\")) {\n                signKey = signKey.substring(KEY.length() + 1);\n                long timestamp = Long.parseLong(signKey.substring(0, signKey.indexOf('|')));\n                if (expiredTime > 0 && System.currentTimeMillis() - timestamp > expiredTime) {\n                    return null;\n                }\n                String id = signKey.substring(signKey.indexOf('|') + 1);\n                return id;\n            }\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            //e.printStackTrace();\n        }\n        return null;\n    }\n    public static String getToken(String username) {\n        String signKey = KEY + \"|\" + (System.currentTimeMillis()) + \"|\" + username;\n        try {\n            return DES.encryptDES(signKey);\n        } catch (Exception e) {\n            // TODO Auto-generated catch block\n            e.printStackTrace();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttCodecUtil.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.DecoderException;\nimport io.netty.util.Attribute;\nimport io.netty.util.AttributeKey;\n\nfinal class MqttCodecUtil {\n\n    private static final char[] TOPIC_WILDCARDS = {'#', '+'};\n\n    static final AttributeKey<MqttVersion> MQTT_VERSION_KEY = AttributeKey.valueOf(\"NETTY_CODEC_MQTT_VERSION\");\n\n    static MqttVersion getMqttVersion(ChannelHandlerContext ctx) {\n        Attribute<MqttVersion> attr = ctx.channel().attr(MQTT_VERSION_KEY);\n        MqttVersion version = attr.get();\n        if (version == null) {\n            return MqttVersion.MQTT_3_1_1;\n        }\n        return version;\n    }\n\n    static void setMqttVersion(ChannelHandlerContext ctx, MqttVersion version) {\n        Attribute<MqttVersion> attr = ctx.channel().attr(MQTT_VERSION_KEY);\n        attr.set(version);\n    }\n\n    static boolean isValidPublishTopicName(String topicName) {\n        // publish topic name must not contain any wildcard\n        for (char c : TOPIC_WILDCARDS) {\n            if (topicName.indexOf(c) >= 0) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    static boolean isValidMessageId(int messageId) {\n        return messageId != 0;\n    }\n\n    static boolean isValidClientId(MqttVersion mqttVersion, int maxClientIdLength, String clientId) {\n        if (mqttVersion == MqttVersion.MQTT_3_1) {\n            return clientId != null && clientId.length() >= MqttConstant.MIN_CLIENT_ID_LENGTH &&\n                clientId.length() <= maxClientIdLength;\n        }\n        if (mqttVersion.protocolLevel() >= MqttVersion.MQTT_3_1_1.protocolLevel()) {\n            // In 3.1.3.1 Client Identifier of MQTT 3.1.1 and 5.0 specifications, The Server MAY allow ClientId’s\n            // that contain more than 23 encoded bytes. And, The Server MAY allow zero-length ClientId.\n            return clientId != null;\n        }\n        throw new IllegalArgumentException(mqttVersion + \" is unknown mqtt version\");\n    }\n\n    static MqttFixedHeader validateFixedHeader(ChannelHandlerContext ctx, MqttFixedHeader mqttFixedHeader) {\n        switch (mqttFixedHeader.messageType()) {\n            case PUBREL:\n            case SUBSCRIBE:\n            case UNSUBSCRIBE:\n                if (mqttFixedHeader.qosLevel() != MqttQoS.AT_LEAST_ONCE) {\n                    throw new DecoderException(mqttFixedHeader.messageType().name() + \" message must have QoS 1\");\n                }\n                return mqttFixedHeader;\n            case AUTH:\n                if (MqttCodecUtil.getMqttVersion(ctx) != MqttVersion.MQTT_5) {\n                    throw new DecoderException(\"AUTH message requires at least MQTT 5\");\n                }\n                return mqttFixedHeader;\n            default:\n                return mqttFixedHeader;\n        }\n    }\n\n    static MqttFixedHeader resetUnusedFields(MqttFixedHeader mqttFixedHeader) {\n        switch (mqttFixedHeader.messageType()) {\n            case CONNECT:\n            case CONNACK:\n            case PUBACK:\n            case PUBREC:\n            case PUBCOMP:\n            case SUBACK:\n            case UNSUBACK:\n            case PINGREQ:\n            case PINGRESP:\n            case DISCONNECT:\n                if (mqttFixedHeader.isDup() ||\n                        mqttFixedHeader.qosLevel() != MqttQoS.AT_MOST_ONCE ||\n                        mqttFixedHeader.isRetain()) {\n                    return new MqttFixedHeader(\n                            mqttFixedHeader.messageType(),\n                            false,\n                            MqttQoS.AT_MOST_ONCE,\n                            false,\n                            mqttFixedHeader.remainingLength());\n                }\n                return mqttFixedHeader;\n            case PUBREL:\n            case SUBSCRIBE:\n            case UNSUBSCRIBE:\n                if (mqttFixedHeader.isRetain()) {\n                    return new MqttFixedHeader(\n                            mqttFixedHeader.messageType(),\n                            mqttFixedHeader.isDup(),\n                            mqttFixedHeader.qosLevel(),\n                            false,\n                            mqttFixedHeader.remainingLength());\n                }\n                return mqttFixedHeader;\n            default:\n                return mqttFixedHeader;\n        }\n    }\n\n    private MqttCodecUtil() { }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttConnAckMessage.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\n/**\n * See <a href=\"https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#connack\">MQTTV3.1/connack</a>\n */\npublic final class MqttConnAckMessage extends MqttMessage {\n\n    public MqttConnAckMessage(MqttFixedHeader mqttFixedHeader, MqttConnAckVariableHeader variableHeader) {\n        super(mqttFixedHeader, variableHeader);\n    }\n\n    public MqttConnAckMessage(MqttFixedHeader mqttFixedHeader, MqttConnAckVariableHeader variableHeader, MqttConnectAckPayload payload) {\n        super(mqttFixedHeader, variableHeader, payload);\n    }\n    \n    @Override\n    public MqttConnAckVariableHeader variableHeader() {\n        return (MqttConnAckVariableHeader) super.variableHeader();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttConnAckVariableHeader.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.StringUtil;\n\n/**\n * Variable header of {@link MqttConnectMessage}\n */\npublic final class MqttConnAckVariableHeader {\n\n    private final MqttConnectReturnCode connectReturnCode;\n\n    private final boolean sessionPresent;\n\n    private final MqttProperties properties;\n\n    public MqttConnAckVariableHeader(MqttConnectReturnCode connectReturnCode, boolean sessionPresent) {\n        this(connectReturnCode, sessionPresent, MqttProperties.NO_PROPERTIES);\n    }\n\n    public MqttConnAckVariableHeader(MqttConnectReturnCode connectReturnCode, boolean sessionPresent,\n                                     MqttProperties properties) {\n        this.connectReturnCode = connectReturnCode;\n        this.sessionPresent = sessionPresent;\n        this.properties = MqttProperties.withEmptyDefaults(properties);\n    }\n\n    public MqttConnectReturnCode connectReturnCode() {\n        return connectReturnCode;\n    }\n\n    public boolean isSessionPresent() {\n        return sessionPresent;\n    }\n\n    public MqttProperties properties() {\n        return properties;\n    }\n\n    @Override\n    public String toString() {\n        return new StringBuilder(StringUtil.simpleClassName(this))\n            .append('[')\n            .append(\"connectReturnCode=\").append(connectReturnCode)\n            .append(\", sessionPresent=\").append(sessionPresent)\n            .append(']')\n            .toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttConnectAckPayload.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. 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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.StringUtil;\n\n/**\n * Payload of {@link MqttConnectMessage}\n */\npublic final class MqttConnectAckPayload {\n\n    private final byte[] data;\n\n    public MqttConnectAckPayload(\n            byte[] data) {\n        this.data = data;\n    }\n\n    public byte[] getData() {\n        return data;\n    }\n\n    @Override\n    public String toString() {\n        return new StringBuilder(StringUtil.simpleClassName(this))\n            .append('[')\n            .append(\"data=\").append(data)\n            .append(']')\n            .toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttConnectMessage.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\n/**\n * See <a href=\"https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#connect\">MQTTV3.1/connect</a>\n */\npublic final class MqttConnectMessage extends MqttMessage {\n\n    public MqttConnectMessage(\n            MqttFixedHeader mqttFixedHeader,\n            MqttConnectVariableHeader variableHeader,\n            MqttConnectPayload payload) {\n        super(mqttFixedHeader, variableHeader, payload);\n    }\n\n    @Override\n    public MqttConnectVariableHeader variableHeader() {\n        return (MqttConnectVariableHeader) super.variableHeader();\n    }\n\n    @Override\n    public MqttConnectPayload payload() {\n        return (MqttConnectPayload) super.payload();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttConnectPayload.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport java.util.Arrays;\n\nimport io.netty.util.CharsetUtil;\nimport io.netty.util.internal.StringUtil;\n\n/**\n * Payload of {@link MqttConnectMessage}\n */\npublic final class MqttConnectPayload {\n\n    private final String clientIdentifier;\n    private final MqttProperties willProperties;\n    private final String willTopic;\n    private final byte[] willMessage;\n    private final String userName;\n    private final byte[] password;\n    private final byte[] signature;\n\n    /**\n     * @deprecated use {@link MqttConnectPayload#MqttConnectPayload(String,\n     * MqttProperties, String, byte[], String, byte[])} instead\n     */\n    @Deprecated\n    public MqttConnectPayload(\n            String clientIdentifier,\n            String willTopic,\n            String willMessage,\n            String userName,\n            String password) {\n        this(\n          clientIdentifier,\n          MqttProperties.NO_PROPERTIES,\n          willTopic,\n          willMessage.getBytes(CharsetUtil.UTF_8),\n          userName,\n          password.getBytes(CharsetUtil.UTF_8), null);\n    }\n\n    public MqttConnectPayload(\n            String clientIdentifier,\n            String willTopic,\n            byte[] willMessage,\n            String userName,\n            byte[] password) {\n        this(clientIdentifier,\n                MqttProperties.NO_PROPERTIES,\n                willTopic,\n                willMessage,\n                userName,\n                password, null);\n    }\n\n    public MqttConnectPayload(\n            String clientIdentifier,\n            MqttProperties willProperties,\n            String willTopic,\n            byte[] willMessage,\n            String userName,\n            byte[] password,\n            byte[] signature) {\n        this.clientIdentifier = clientIdentifier;\n        this.willProperties = MqttProperties.withEmptyDefaults(willProperties);\n        this.willTopic = willTopic;\n        this.willMessage = willMessage;\n        this.userName = userName;\n        this.password = password;\n        this.signature = signature;\n    }\n\n    public String clientIdentifier() {\n        return clientIdentifier;\n    }\n\n    public MqttProperties willProperties() {\n        return willProperties;\n    }\n\n    public String willTopic() {\n        return willTopic;\n    }\n\n    /**\n     * @deprecated use {@link MqttConnectPayload#willMessageInBytes()} instead\n     */\n    @Deprecated\n    public String willMessage() {\n        return willMessage == null ? null : new String(willMessage, CharsetUtil.UTF_8);\n    }\n\n    public byte[] willMessageInBytes() {\n        return willMessage;\n    }\n\n    public String userName() {\n        return userName;\n    }\n\n    /**\n     * @deprecated use {@link MqttConnectPayload#passwordInBytes()} instead\n     */\n    @Deprecated\n    public String password() {\n        return password == null ? null : new String(password, CharsetUtil.UTF_8);\n    }\n\n    public byte[] passwordInBytes() {\n        return password;\n    }\n\n    public byte[] signatureInBytes() {\n        return signature;\n    }\n\n    @Override\n    public String toString() {\n        return new StringBuilder(StringUtil.simpleClassName(this))\n            .append('[')\n            .append(\"clientIdentifier=\").append(clientIdentifier)\n            .append(\", willTopic=\").append(willTopic)\n            .append(\", willMessage=\").append(Arrays.toString(willMessage))\n            .append(\", userName=\").append(userName)\n            .append(\", password=\").append(Arrays.toString(password))\n            .append(']')\n            .toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttConnectReturnCode.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\n/**\n * Return Code of {@link MqttConnAckMessage}\n */\npublic enum MqttConnectReturnCode {\n    CONNECTION_ACCEPTED((byte) 0x00),\n    //MQTT 3 codes\n    CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL_VERSION((byte) 0X01),\n    CONNECTION_REFUSED_IDENTIFIER_REJECTED((byte) 0x02),\n    CONNECTION_REFUSED_SERVER_UNAVAILABLE((byte) 0x03),\n    CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD((byte) 0x04),\n    CONNECTION_REFUSED_NOT_AUTHORIZED((byte) 0x05),\n    CONNECTION_REFUSED_UNEXPECT_NODE((byte) 0X06),\n    CONNECTION_REFUSED_SESSION_NOT_EXIST((byte) 0x07),\n    CONNECTION_REFUSED_SIGNATURE_FAILURE((byte) 0x08),\n    //MQTT 5 codes\n    CONNECTION_REFUSED_UNSPECIFIED_ERROR((byte) 0x80),\n    CONNECTION_REFUSED_MALFORMED_PACKET((byte) 0x81),\n    CONNECTION_REFUSED_PROTOCOL_ERROR((byte) 0x82),\n    CONNECTION_REFUSED_IMPLEMENTATION_SPECIFIC((byte) 0x83),\n    CONNECTION_REFUSED_UNSUPPORTED_PROTOCOL_VERSION((byte) 0x84),\n    CONNECTION_REFUSED_CLIENT_IDENTIFIER_NOT_VALID((byte) 0x85),\n    CONNECTION_REFUSED_BAD_USERNAME_OR_PASSWORD((byte) 0x86),\n    CONNECTION_REFUSED_NOT_AUTHORIZED_5((byte) 0x87),\n    CONNECTION_REFUSED_SERVER_UNAVAILABLE_5((byte) 0x88),\n    CONNECTION_REFUSED_SERVER_BUSY((byte) 0x89),\n    CONNECTION_REFUSED_BANNED((byte) 0x8A),\n    CONNECTION_REFUSED_BAD_AUTHENTICATION_METHOD((byte) 0x8C),\n    CONNECTION_REFUSED_TOPIC_NAME_INVALID((byte) 0x90),\n    CONNECTION_REFUSED_PACKET_TOO_LARGE((byte) 0x95),\n    CONNECTION_REFUSED_QUOTA_EXCEEDED((byte) 0x97),\n    CONNECTION_REFUSED_PAYLOAD_FORMAT_INVALID((byte) 0x99),\n    CONNECTION_REFUSED_RETAIN_NOT_SUPPORTED((byte) 0x9A),\n    CONNECTION_REFUSED_QOS_NOT_SUPPORTED((byte) 0x9B),\n    CONNECTION_REFUSED_USE_ANOTHER_SERVER((byte) 0x9C),\n    CONNECTION_REFUSED_SERVER_MOVED((byte) 0x9D),\n    CONNECTION_REFUSED_CONNECTION_RATE_EXCEEDED((byte) 0x9F);\n\n    private static final MqttConnectReturnCode[] VALUES;\n\n    static {\n        MqttConnectReturnCode[] values = values();\n        VALUES = new MqttConnectReturnCode[160];\n        for (MqttConnectReturnCode code : values) {\n            final int unsignedByte = code.byteValue & 0xFF;\n            // Suppress a warning about out of bounds access since the enum contains only correct values\n            VALUES[unsignedByte] = code;    // lgtm [java/index-out-of-bounds]\n        }\n    }\n\n    private final byte byteValue;\n\n    MqttConnectReturnCode(byte byteValue) {\n        this.byteValue = byteValue;\n    }\n\n    public byte byteValue() {\n        return byteValue;\n    }\n\n    public static MqttConnectReturnCode valueOf(byte b) {\n        final int unsignedByte = b & 0xFF;\n        MqttConnectReturnCode mqttConnectReturnCode = null;\n        try {\n            mqttConnectReturnCode = VALUES[unsignedByte];\n        } catch (ArrayIndexOutOfBoundsException ignored) {\n            // no op\n        }\n        if (mqttConnectReturnCode == null) {\n            throw new IllegalArgumentException(\"unknown connect return code: \" + unsignedByte);\n        }\n        return mqttConnectReturnCode;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttConnectVariableHeader.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.StringUtil;\n\n/**\n * Variable Header for the {@link MqttConnectMessage}\n */\npublic final class MqttConnectVariableHeader {\n\n    private final String name;\n    private final int version;\n    private final boolean hasUserName;\n    private final boolean hasPassword;\n    private final boolean isWillRetain;\n    private final int willQos;\n    private final boolean isWillFlag;\n    private final boolean isCleanSession;\n    private final int keepAliveTimeSeconds;\n    private final MqttProperties properties;\n\n    public MqttConnectVariableHeader(\n            String name,\n            int version,\n            boolean hasUserName,\n            boolean hasPassword,\n            boolean isWillRetain,\n            int willQos,\n            boolean isWillFlag,\n            boolean isCleanSession,\n            int keepAliveTimeSeconds) {\n        this(name,\n                version,\n                hasUserName,\n                hasPassword,\n                isWillRetain,\n                willQos,\n                isWillFlag,\n                isCleanSession,\n                keepAliveTimeSeconds,\n                MqttProperties.NO_PROPERTIES);\n    }\n\n    public MqttConnectVariableHeader(\n            String name,\n            int version,\n            boolean hasUserName,\n            boolean hasPassword,\n            boolean isWillRetain,\n            int willQos,\n            boolean isWillFlag,\n            boolean isCleanSession,\n            int keepAliveTimeSeconds,\n            MqttProperties properties) {\n        this.name = name;\n        this.version = version;\n        this.hasUserName = hasUserName;\n        this.hasPassword = hasPassword;\n        this.isWillRetain = isWillRetain;\n        this.willQos = willQos;\n        this.isWillFlag = isWillFlag;\n        this.isCleanSession = isCleanSession;\n        this.keepAliveTimeSeconds = keepAliveTimeSeconds;\n        this.properties = MqttProperties.withEmptyDefaults(properties);\n    }\n\n    public String name() {\n        return name;\n    }\n\n    public int version() {\n        return version;\n    }\n\n    public boolean hasUserName() {\n        return hasUserName;\n    }\n\n    public boolean hasPassword() {\n        return hasPassword;\n    }\n\n    public boolean isWillRetain() {\n        return isWillRetain;\n    }\n\n    public int willQos() {\n        return willQos;\n    }\n\n    public boolean isWillFlag() {\n        return isWillFlag;\n    }\n\n    public boolean isCleanSession() {\n        return isCleanSession;\n    }\n\n    public int keepAliveTimeSeconds() {\n        return keepAliveTimeSeconds;\n    }\n\n    public MqttProperties properties() {\n        return properties;\n    }\n\n    @Override\n    public String toString() {\n        return new StringBuilder(StringUtil.simpleClassName(this))\n            .append('[')\n            .append(\"name=\").append(name)\n            .append(\", version=\").append(version)\n            .append(\", hasUserName=\").append(hasUserName)\n            .append(\", hasPassword=\").append(hasPassword)\n            .append(\", isWillRetain=\").append(isWillRetain)\n            .append(\", isWillFlag=\").append(isWillFlag)\n            .append(\", isCleanSession=\").append(isCleanSession)\n            .append(\", keepAliveTimeSeconds=\").append(keepAliveTimeSeconds)\n            .append(']')\n            .toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttConstant.java",
    "content": "/*\n * Copyright 2021 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage io.netty.handler.codec.mqtt;\n\npublic final class MqttConstant {\n\n    private MqttConstant() {\n    }\n\n    /**\n     * Default max bytes in message\n     */\n    public static final int DEFAULT_MAX_BYTES_IN_MESSAGE = 262144; //256KB\n\n    /**\n     * min client id length\n     */\n    public static final int MIN_CLIENT_ID_LENGTH = 1;\n\n    /**\n     * Default max client id length,In the mqtt3.1 protocol,\n     * the default maximum Client Identifier length is 23\n     */\n    public static final int DEFAULT_MAX_CLIENT_ID_LENGTH = 23;\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttDecoder.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.DecoderException;\nimport io.netty.handler.codec.ReplayingDecoder;\nimport io.netty.handler.codec.TooLongFrameException;\nimport io.netty.util.CharsetUtil;\nimport io.netty.util.internal.ObjectUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Decodes Mqtt messages from bytes, following\n * the MQTT protocol specification\n * <a href=\"https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html\">v3.1</a>\n * or\n * <a href=\"https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html\">v5.0</a>, depending on the\n * version specified in the CONNECT message that first goes through the channel.\n */\npublic final class MqttDecoder extends ReplayingDecoder<MqttDecoder.DecoderState> {\n\n    /**\n     * States of the decoder.\n     * We start at READ_FIXED_HEADER, followed by\n     * READ_VARIABLE_HEADER and finally READ_PAYLOAD.\n     */\n    enum DecoderState {\n        READ_FIXED_HEADER,\n        READ_VARIABLE_HEADER,\n        READ_PAYLOAD,\n        BAD_MESSAGE,\n    }\n\n    private MqttFixedHeader mqttFixedHeader;\n    private Object variableHeader;\n    private int bytesRemainingInVariablePart;\n\n    private final int maxBytesInMessage;\n    private final int maxClientIdLength;\n\n    public MqttDecoder() {\n      this(MqttConstant.DEFAULT_MAX_BYTES_IN_MESSAGE, MqttConstant.DEFAULT_MAX_CLIENT_ID_LENGTH);\n    }\n\n    public MqttDecoder(int maxBytesInMessage) {\n        this(maxBytesInMessage, MqttConstant.DEFAULT_MAX_CLIENT_ID_LENGTH);\n    }\n\n    public MqttDecoder(int maxBytesInMessage, int maxClientIdLength) {\n        super(DecoderState.READ_FIXED_HEADER);\n        this.maxBytesInMessage = ObjectUtil.checkPositive(maxBytesInMessage, \"maxBytesInMessage\");\n        this.maxClientIdLength = ObjectUtil.checkPositive(maxClientIdLength, \"maxClientIdLength\");\n    }\n\n    @Override\n    protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {\n        switch (state()) {\n            case READ_FIXED_HEADER: try {\n                mqttFixedHeader = decodeFixedHeader(ctx, buffer);\n                bytesRemainingInVariablePart = mqttFixedHeader.remainingLength();\n                checkpoint(DecoderState.READ_VARIABLE_HEADER);\n                // fall through\n            } catch (Exception cause) {\n                out.add(invalidMessage(cause));\n                return;\n            }\n\n            case READ_VARIABLE_HEADER:  try {\n                final Result<?> decodedVariableHeader = decodeVariableHeader(ctx, buffer, mqttFixedHeader);\n                variableHeader = decodedVariableHeader.value;\n                if (bytesRemainingInVariablePart > maxBytesInMessage) {\n                    buffer.skipBytes(actualReadableBytes());\n                    throw new TooLongFrameException(\"too large message: \" + bytesRemainingInVariablePart + \" bytes\");\n                }\n                bytesRemainingInVariablePart -= decodedVariableHeader.numberOfBytesConsumed;\n                checkpoint(DecoderState.READ_PAYLOAD);\n                // fall through\n            } catch (Exception cause) {\n                out.add(invalidMessage(cause));\n                return;\n            }\n\n            case READ_PAYLOAD: try {\n                final Result<?> decodedPayload =\n                        decodePayload(\n                                ctx,\n                                buffer,\n                                mqttFixedHeader.messageType(),\n                                bytesRemainingInVariablePart,\n                                maxClientIdLength,\n                                variableHeader);\n                bytesRemainingInVariablePart -= decodedPayload.numberOfBytesConsumed;\n                if (bytesRemainingInVariablePart != 0) {\n                    throw new DecoderException(\n                            \"non-zero remaining payload bytes: \" +\n                                    bytesRemainingInVariablePart + \" (\" + mqttFixedHeader.messageType() + ')');\n                }\n                checkpoint(DecoderState.READ_FIXED_HEADER);\n                MqttMessage message = MqttMessageFactory.newMessage(\n                        mqttFixedHeader, variableHeader, decodedPayload.value);\n                mqttFixedHeader = null;\n                variableHeader = null;\n                out.add(message);\n                break;\n            } catch (Exception cause) {\n                out.add(invalidMessage(cause));\n                return;\n            }\n\n            case BAD_MESSAGE:\n                // Keep discarding until disconnection.\n                buffer.skipBytes(actualReadableBytes());\n                break;\n\n            default:\n                // Shouldn't reach here.\n                throw new Error();\n        }\n    }\n\n    private MqttMessage invalidMessage(Throwable cause) {\n      checkpoint(DecoderState.BAD_MESSAGE);\n      return MqttMessageFactory.newInvalidMessage(mqttFixedHeader, variableHeader, cause);\n    }\n\n    /**\n     * Decodes the fixed header. It's one byte for the flags and then variable\n     * bytes for the remaining length.\n     *\n     * @see\n     * <a href=\"https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html#_Toc442180841\">...</a>\n     *\n     * @param buffer the buffer to decode from\n     * @return the fixed header\n     */\n    private static MqttFixedHeader decodeFixedHeader(ChannelHandlerContext ctx, ByteBuf buffer) {\n        short b1 = buffer.readUnsignedByte();\n\n        MqttMessageType messageType = MqttMessageType.valueOf(b1 >> 4);\n        boolean dupFlag = (b1 & 0x08) == 0x08;\n        int qosLevel = (b1 & 0x06) >> 1;\n        boolean retain = (b1 & 0x01) != 0;\n\n        switch (messageType) {\n            case PUBLISH:\n                if (qosLevel == 3) {\n                    throw new DecoderException(\"Illegal QOS Level in fixed header of PUBLISH message (\"\n                            + qosLevel + ')');\n                }\n                break;\n\n            case PUBREL:\n            case SUBSCRIBE:\n            case UNSUBSCRIBE:\n                if (dupFlag) {\n                    throw new DecoderException(\"Illegal BIT 3 in fixed header of \" + messageType\n                            + \" message, must be 0, found 1\");\n                }\n                if (qosLevel != 1) {\n                    throw new DecoderException(\"Illegal QOS Level in fixed header of \" + messageType\n                            + \" message, must be 1, found \" + qosLevel);\n                }\n                if (retain) {\n                    throw new DecoderException(\"Illegal BIT 0 in fixed header of \" + messageType\n                            + \" message, must be 0, found 1\");\n                }\n                break;\n\n            case AUTH:\n            case CONNACK:\n            case CONNECT:\n            case DISCONNECT:\n            case PINGREQ:\n            case PINGRESP:\n            case PUBACK:\n            case PUBCOMP:\n            case PUBREC:\n            case SUBACK:\n            case UNSUBACK:\n                if (dupFlag) {\n                    throw new DecoderException(\"Illegal BIT 3 in fixed header of \" + messageType\n                            + \" message, must be 0, found 1\");\n                }\n                if (qosLevel != 0) {\n                    throw new DecoderException(\"Illegal BIT 2 or 1 in fixed header of \" + messageType\n                            + \" message, must be 0, found \" + qosLevel);\n                }\n                if (retain) {\n                    throw new DecoderException(\"Illegal BIT 0 in fixed header of \" + messageType\n                            + \" message, must be 0, found 1\");\n                }\n                break;\n            default:\n                throw new DecoderException(\"Unknown message type, do not know how to validate fixed header\");\n        }\n\n        int remainingLength = 0;\n        int multiplier = 1;\n        short digit;\n        int loops = 0;\n        do {\n            digit = buffer.readUnsignedByte();\n            remainingLength += (digit & 127) * multiplier;\n            multiplier *= 128;\n            loops++;\n        } while ((digit & 128) != 0 && loops < 4);\n\n        // MQTT protocol limits Remaining Length to 4 bytes\n        if (loops == 4 && (digit & 128) != 0) {\n            throw new DecoderException(\"remaining length exceeds 4 digits (\" + messageType + ')');\n        }\n        MqttFixedHeader decodedFixedHeader =\n                new MqttFixedHeader(messageType, dupFlag, MqttQoS.valueOf(qosLevel), retain, remainingLength);\n        return MqttCodecUtil.validateFixedHeader(ctx, MqttCodecUtil.resetUnusedFields(decodedFixedHeader));\n    }\n\n    /**\n     * Decodes the variable header (if any)\n     * @param buffer the buffer to decode from\n     * @param mqttFixedHeader MqttFixedHeader of the same message\n     * @return the variable header\n     */\n    private Result<?> decodeVariableHeader(ChannelHandlerContext ctx, ByteBuf buffer, MqttFixedHeader mqttFixedHeader) {\n        switch (mqttFixedHeader.messageType()) {\n            case CONNECT:\n                return decodeConnectionVariableHeader(ctx, buffer);\n\n            case CONNACK:\n                return decodeConnAckVariableHeader(ctx, buffer);\n\n            case UNSUBSCRIBE:\n            case SUBSCRIBE:\n            case SUBACK:\n            case UNSUBACK:\n                return decodeMessageIdAndPropertiesVariableHeader(ctx, buffer);\n\n            case PUBACK:\n            case PUBREC:\n            case PUBCOMP:\n            case PUBREL:\n                return decodePubReplyMessage(buffer);\n\n            case PUBLISH:\n                return decodePublishVariableHeader(ctx, buffer, mqttFixedHeader);\n\n            case DISCONNECT:\n            case AUTH:\n                return decodeReasonCodeAndPropertiesVariableHeader(buffer);\n\n            case PINGREQ:\n            case PINGRESP:\n                // Empty variable header\n                return new Result<Object>(null, 0);\n            default:\n                //shouldn't reach here\n                throw new DecoderException(\"Unknown message type: \" + mqttFixedHeader.messageType());\n        }\n    }\n\n    private static Result<MqttConnectVariableHeader> decodeConnectionVariableHeader(\n            ChannelHandlerContext ctx,\n            ByteBuf buffer) {\n        final Result<String> protoString = decodeString(buffer);\n        int numberOfBytesConsumed = protoString.numberOfBytesConsumed;\n\n        final byte protocolLevel = buffer.readByte();\n        numberOfBytesConsumed += 1;\n\n        MqttVersion version = MqttVersion.fromProtocolNameAndLevel(protoString.value, protocolLevel);\n        MqttCodecUtil.setMqttVersion(ctx, version);\n\n        final int b1 = buffer.readUnsignedByte();\n        numberOfBytesConsumed += 1;\n\n        final int keepAlive = decodeMsbLsb(buffer);\n        numberOfBytesConsumed += 2;\n\n        final boolean hasUserName = (b1 & 0x80) == 0x80;\n        final boolean hasPassword = (b1 & 0x40) == 0x40;\n        final boolean willRetain = (b1 & 0x20) == 0x20;\n        final int willQos = (b1 & 0x18) >> 3;\n        final boolean willFlag = (b1 & 0x04) == 0x04;\n        final boolean cleanSession = (b1 & 0x02) == 0x02;\n        if (version == MqttVersion.MQTT_3_1_1 || version == MqttVersion.MQTT_5) {\n            final boolean zeroReservedFlag = (b1 & 0x01) == 0x0;\n            if (!zeroReservedFlag) {\n                // MQTT v3.1.1: The Server MUST validate that the reserved flag in the CONNECT Control Packet is\n                // set to zero and disconnect the Client if it is not zero.\n                // See https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc385349230\n                throw new DecoderException(\"non-zero reserved flag\");\n            }\n        }\n\n        final MqttProperties properties;\n        if (version == MqttVersion.MQTT_5) {\n            final Result<MqttProperties> propertiesResult = decodeProperties(buffer);\n            properties = propertiesResult.value;\n            numberOfBytesConsumed += propertiesResult.numberOfBytesConsumed;\n        } else {\n            properties = MqttProperties.NO_PROPERTIES;\n        }\n\n        final MqttConnectVariableHeader mqttConnectVariableHeader = new MqttConnectVariableHeader(\n                version.protocolName(),\n                version.protocolLevel(),\n                hasUserName,\n                hasPassword,\n                willRetain,\n                willQos,\n                willFlag,\n                cleanSession,\n                keepAlive,\n                properties);\n        return new Result<MqttConnectVariableHeader>(mqttConnectVariableHeader, numberOfBytesConsumed);\n    }\n\n    private static Result<MqttConnAckVariableHeader> decodeConnAckVariableHeader(\n            ChannelHandlerContext ctx,\n            ByteBuf buffer) {\n        final MqttVersion mqttVersion = MqttCodecUtil.getMqttVersion(ctx);\n        final boolean sessionPresent = (buffer.readUnsignedByte() & 0x01) == 0x01;\n        byte returnCode = buffer.readByte();\n        int numberOfBytesConsumed = 2;\n\n        final MqttProperties properties;\n        if (mqttVersion == MqttVersion.MQTT_5) {\n            final Result<MqttProperties> propertiesResult = decodeProperties(buffer);\n            properties = propertiesResult.value;\n            numberOfBytesConsumed += propertiesResult.numberOfBytesConsumed;\n        } else {\n            properties = MqttProperties.NO_PROPERTIES;\n        }\n\n        final MqttConnAckVariableHeader mqttConnAckVariableHeader =\n                new MqttConnAckVariableHeader(MqttConnectReturnCode.valueOf(returnCode), sessionPresent, properties);\n        return new Result<MqttConnAckVariableHeader>(mqttConnAckVariableHeader, numberOfBytesConsumed);\n    }\n\n    private static Result<MqttMessageIdAndPropertiesVariableHeader> decodeMessageIdAndPropertiesVariableHeader(\n            ChannelHandlerContext ctx,\n            ByteBuf buffer) {\n        final MqttVersion mqttVersion = MqttCodecUtil.getMqttVersion(ctx);\n        final int packetId = decodeMessageId(buffer);\n\n        final MqttMessageIdAndPropertiesVariableHeader mqttVariableHeader;\n        final int mqtt5Consumed;\n\n        if (mqttVersion == MqttVersion.MQTT_5) {\n            final Result<MqttProperties> properties = decodeProperties(buffer);\n            mqttVariableHeader = new MqttMessageIdAndPropertiesVariableHeader(packetId, properties.value);\n            mqtt5Consumed = properties.numberOfBytesConsumed;\n        } else {\n            mqttVariableHeader = new MqttMessageIdAndPropertiesVariableHeader(packetId,\n                    MqttProperties.NO_PROPERTIES);\n            mqtt5Consumed = 0;\n        }\n\n        return new Result<MqttMessageIdAndPropertiesVariableHeader>(mqttVariableHeader,\n                2 + mqtt5Consumed);\n    }\n\n    private Result<MqttPubReplyMessageVariableHeader> decodePubReplyMessage(ByteBuf buffer) {\n        final int packetId = decodeMessageId(buffer);\n\n        final MqttPubReplyMessageVariableHeader mqttPubAckVariableHeader;\n        final int consumed;\n        final int packetIdNumberOfBytesConsumed = 2;\n        if (bytesRemainingInVariablePart > 3) {\n            final byte reasonCode = buffer.readByte();\n            final Result<MqttProperties> properties = decodeProperties(buffer);\n            mqttPubAckVariableHeader = new MqttPubReplyMessageVariableHeader(packetId,\n                    reasonCode,\n                    properties.value);\n            consumed = packetIdNumberOfBytesConsumed + 1 + properties.numberOfBytesConsumed;\n        } else if (bytesRemainingInVariablePart > 2) {\n            final byte reasonCode = buffer.readByte();\n            mqttPubAckVariableHeader = new MqttPubReplyMessageVariableHeader(packetId,\n                    reasonCode,\n                    MqttProperties.NO_PROPERTIES);\n            consumed = packetIdNumberOfBytesConsumed + 1;\n        } else {\n            mqttPubAckVariableHeader = new MqttPubReplyMessageVariableHeader(packetId,\n                    (byte) 0,\n                    MqttProperties.NO_PROPERTIES);\n            consumed = packetIdNumberOfBytesConsumed;\n        }\n\n        return new Result<MqttPubReplyMessageVariableHeader>(mqttPubAckVariableHeader, consumed);\n    }\n\n    private Result<MqttReasonCodeAndPropertiesVariableHeader> decodeReasonCodeAndPropertiesVariableHeader(\n            ByteBuf buffer) {\n        final byte reasonCode;\n        final MqttProperties properties;\n        final int consumed;\n        if (bytesRemainingInVariablePart > 1) {\n            reasonCode = buffer.readByte();\n            final Result<MqttProperties> propertiesResult = decodeProperties(buffer);\n            properties = propertiesResult.value;\n            consumed = 1 + propertiesResult.numberOfBytesConsumed;\n        } else if (bytesRemainingInVariablePart > 0) {\n            reasonCode = buffer.readByte();\n            properties = MqttProperties.NO_PROPERTIES;\n            consumed = 1;\n        } else {\n            reasonCode = 0;\n            properties = MqttProperties.NO_PROPERTIES;\n            consumed = 0;\n        }\n        final MqttReasonCodeAndPropertiesVariableHeader mqttReasonAndPropsVariableHeader =\n                new MqttReasonCodeAndPropertiesVariableHeader(reasonCode, properties);\n\n        return new Result<MqttReasonCodeAndPropertiesVariableHeader>(\n                mqttReasonAndPropsVariableHeader,\n                consumed);\n    }\n\n    private Result<MqttPublishVariableHeader> decodePublishVariableHeader(\n            ChannelHandlerContext ctx,\n            ByteBuf buffer,\n            MqttFixedHeader mqttFixedHeader) {\n        final MqttVersion mqttVersion = MqttCodecUtil.getMqttVersion(ctx);\n        final Result<String> decodedTopic = decodeString(buffer);\n        if (!MqttCodecUtil.isValidPublishTopicName(decodedTopic.value)) {\n            throw new DecoderException(\"invalid publish topic name: \" + decodedTopic.value + \" (contains wildcards)\");\n        }\n        int numberOfBytesConsumed = decodedTopic.numberOfBytesConsumed;\n\n        int messageId = -1;\n        if (mqttFixedHeader.qosLevel().value() > 0) {\n            messageId = decodeMessageId(buffer);\n            numberOfBytesConsumed += 2;\n        }\n\n        final MqttProperties properties;\n        if (mqttVersion == MqttVersion.MQTT_5) {\n            final Result<MqttProperties> propertiesResult = decodeProperties(buffer);\n            properties = propertiesResult.value;\n            numberOfBytesConsumed += propertiesResult.numberOfBytesConsumed;\n        } else {\n            properties = MqttProperties.NO_PROPERTIES;\n        }\n\n        final MqttPublishVariableHeader mqttPublishVariableHeader =\n                new MqttPublishVariableHeader(decodedTopic.value, messageId, properties);\n        return new Result<MqttPublishVariableHeader>(mqttPublishVariableHeader, numberOfBytesConsumed);\n    }\n\n    /**\n     * @return messageId with numberOfBytesConsumed is 2\n     */\n    private static int decodeMessageId(ByteBuf buffer) {\n        final int messageId = decodeMsbLsb(buffer);\n        if (!MqttCodecUtil.isValidMessageId(messageId)) {\n            throw new DecoderException(\"invalid messageId: \" + messageId);\n        }\n        return messageId;\n    }\n\n    /**\n     * Decodes the payload.\n     *\n     * @param buffer the buffer to decode from\n     * @param messageType  type of the message being decoded\n     * @param bytesRemainingInVariablePart bytes remaining\n     * @param variableHeader variable header of the same message\n     * @return the payload\n     */\n    private static Result<?> decodePayload(\n            ChannelHandlerContext ctx,\n            ByteBuf buffer,\n            MqttMessageType messageType,\n            int bytesRemainingInVariablePart,\n            int maxClientIdLength,\n            Object variableHeader) {\n        switch (messageType) {\n            case CONNECT:\n                return decodeConnectionPayload(buffer, maxClientIdLength, (MqttConnectVariableHeader) variableHeader);\n\n            case SUBSCRIBE:\n                return decodeSubscribePayload(buffer, bytesRemainingInVariablePart);\n\n            case SUBACK:\n                return decodeSubackPayload(buffer, bytesRemainingInVariablePart);\n\n            case UNSUBSCRIBE:\n                return decodeUnsubscribePayload(buffer, bytesRemainingInVariablePart);\n\n            case UNSUBACK:\n                return decodeUnsubAckPayload(ctx, buffer, bytesRemainingInVariablePart);\n\n            case PUBLISH:\n                return decodePublishPayload(buffer, bytesRemainingInVariablePart);\n\n            default:\n                // unknown payload , no byte consumed\n                return new Result<Object>(null, 0);\n        }\n    }\n\n    private static Result<MqttConnectPayload> decodeConnectionPayload(\n            ByteBuf buffer,\n            int maxClientIdLength,\n            MqttConnectVariableHeader mqttConnectVariableHeader) {\n        final Result<String> decodedClientId = decodeString(buffer);\n        final String decodedClientIdValue = decodedClientId.value;\n        final MqttVersion mqttVersion = MqttVersion.fromProtocolNameAndLevel(mqttConnectVariableHeader.name(),\n                (byte) mqttConnectVariableHeader.version());\n        if (!MqttCodecUtil.isValidClientId(mqttVersion, maxClientIdLength, decodedClientIdValue)) {\n            throw new MqttIdentifierRejectedException(\"invalid clientIdentifier: \" + decodedClientIdValue);\n        }\n        int numberOfBytesConsumed = decodedClientId.numberOfBytesConsumed;\n\n        Result<String> decodedWillTopic = null;\n        byte[] decodedWillMessage = null;\n\n        final MqttProperties willProperties;\n        if (mqttConnectVariableHeader.isWillFlag()) {\n            if (mqttVersion.protocolLevel() <= MqttVersion.MQTT_5.protocolLevel()) {\n                final Result<MqttProperties> propertiesResult = decodeProperties(buffer);\n                willProperties = propertiesResult.value;\n                numberOfBytesConsumed += propertiesResult.numberOfBytesConsumed;\n            } else {\n                willProperties = MqttProperties.NO_PROPERTIES;\n            }\n            decodedWillTopic = decodeString(buffer, 0, 32767);\n            numberOfBytesConsumed += decodedWillTopic.numberOfBytesConsumed;\n            decodedWillMessage = decodeByteArray(buffer);\n            numberOfBytesConsumed += decodedWillMessage.length + 2;\n        } else {\n            willProperties = MqttProperties.NO_PROPERTIES;\n        }\n        Result<String> decodedUserName = null;\n        byte[] decodedPassword = null;\n        byte[] decodedSignature = null;\n        if (mqttConnectVariableHeader.hasUserName()) {\n            decodedUserName = decodeString(buffer);\n            numberOfBytesConsumed += decodedUserName.numberOfBytesConsumed;\n        }\n        if (mqttConnectVariableHeader.hasPassword()) {\n            decodedPassword = decodeByteArray(buffer);\n            numberOfBytesConsumed += decodedPassword.length + 2;\n        }\n        if (mqttConnectVariableHeader.isWillRetain()) {\n            decodedSignature = decodeByteArray(buffer);\n            numberOfBytesConsumed += decodedSignature.length + 2;\n        }\n\n        final MqttConnectPayload mqttConnectPayload =\n                new MqttConnectPayload(\n                        decodedClientId.value,\n                        willProperties,\n                        decodedWillTopic != null ? decodedWillTopic.value : null,\n                        decodedWillMessage,\n                        decodedUserName != null ? decodedUserName.value : null,\n                        decodedPassword,\n                        decodedSignature\n                    );\n        return new Result<MqttConnectPayload>(mqttConnectPayload, numberOfBytesConsumed);\n    }\n\n    private static Result<MqttSubscribePayload> decodeSubscribePayload(\n            ByteBuf buffer,\n            int bytesRemainingInVariablePart) {\n        final List<MqttTopicSubscription> subscribeTopics = new ArrayList<MqttTopicSubscription>();\n        int numberOfBytesConsumed = 0;\n        while (numberOfBytesConsumed < bytesRemainingInVariablePart) {\n            final Result<String> decodedTopicName = decodeString(buffer);\n            numberOfBytesConsumed += decodedTopicName.numberOfBytesConsumed;\n            //See 3.8.3.1 Subscription Options of MQTT 5.0 specification for optionByte details\n            final short optionByte = buffer.readUnsignedByte();\n\n            MqttQoS qos = MqttQoS.valueOf(optionByte & 0x03);\n            boolean noLocal = ((optionByte & 0x04) >> 2) == 1;\n            boolean retainAsPublished = ((optionByte & 0x08) >> 3) == 1;\n            MqttSubscriptionOption.RetainedHandlingPolicy retainHandling = MqttSubscriptionOption.RetainedHandlingPolicy.valueOf((optionByte & 0x30) >> 4);\n\n            final MqttSubscriptionOption subscriptionOption = new MqttSubscriptionOption(qos,\n                    noLocal,\n                    retainAsPublished,\n                    retainHandling);\n\n            numberOfBytesConsumed++;\n            subscribeTopics.add(new MqttTopicSubscription(decodedTopicName.value, subscriptionOption));\n        }\n        return new Result<MqttSubscribePayload>(new MqttSubscribePayload(subscribeTopics), numberOfBytesConsumed);\n    }\n\n    private static Result<MqttSubAckPayload> decodeSubackPayload(\n            ByteBuf buffer,\n            int bytesRemainingInVariablePart) {\n        final List<Integer> grantedQos = new ArrayList<Integer>(bytesRemainingInVariablePart);\n        int numberOfBytesConsumed = 0;\n        while (numberOfBytesConsumed < bytesRemainingInVariablePart) {\n            int reasonCode = buffer.readUnsignedByte();\n            numberOfBytesConsumed++;\n            grantedQos.add(reasonCode);\n        }\n        return new Result<MqttSubAckPayload>(new MqttSubAckPayload(grantedQos), numberOfBytesConsumed);\n    }\n\n    private static Result<MqttUnsubAckPayload> decodeUnsubAckPayload(\n        ChannelHandlerContext ctx,\n        ByteBuf buffer,\n        int bytesRemainingInVariablePart) {\n        final List<Short> reasonCodes = new ArrayList<Short>(bytesRemainingInVariablePart);\n        int numberOfBytesConsumed = 0;\n        while (numberOfBytesConsumed < bytesRemainingInVariablePart) {\n            short reasonCode = buffer.readUnsignedByte();\n            numberOfBytesConsumed++;\n            reasonCodes.add(reasonCode);\n        }\n        return new Result<MqttUnsubAckPayload>(new MqttUnsubAckPayload(reasonCodes), numberOfBytesConsumed);\n    }\n\n    private static Result<MqttUnsubscribePayload> decodeUnsubscribePayload(\n            ByteBuf buffer,\n            int bytesRemainingInVariablePart) {\n        final List<String> unsubscribeTopics = new ArrayList<String>();\n        int numberOfBytesConsumed = 0;\n        while (numberOfBytesConsumed < bytesRemainingInVariablePart) {\n            final Result<String> decodedTopicName = decodeString(buffer);\n            numberOfBytesConsumed += decodedTopicName.numberOfBytesConsumed;\n            unsubscribeTopics.add(decodedTopicName.value);\n        }\n        return new Result<MqttUnsubscribePayload>(\n                new MqttUnsubscribePayload(unsubscribeTopics),\n                numberOfBytesConsumed);\n    }\n\n    private static Result<ByteBuf> decodePublishPayload(ByteBuf buffer, int bytesRemainingInVariablePart) {\n        ByteBuf b = buffer.readRetainedSlice(bytesRemainingInVariablePart);\n        return new Result<ByteBuf>(b, bytesRemainingInVariablePart);\n    }\n\n    private static Result<String> decodeString(ByteBuf buffer) {\n        return decodeString(buffer, 0, Integer.MAX_VALUE);\n    }\n\n    private static Result<String> decodeString(ByteBuf buffer, int minBytes, int maxBytes) {\n        int size = decodeMsbLsb(buffer);\n        int numberOfBytesConsumed = 2;\n        if (size < minBytes || size > maxBytes) {\n            buffer.skipBytes(size);\n            numberOfBytesConsumed += size;\n            return new Result<String>(null, numberOfBytesConsumed);\n        }\n        String s = buffer.toString(buffer.readerIndex(), size, CharsetUtil.UTF_8);\n        buffer.skipBytes(size);\n        numberOfBytesConsumed += size;\n        return new Result<String>(s, numberOfBytesConsumed);\n    }\n\n    /**\n     *\n     * @return the decoded byte[], numberOfBytesConsumed = byte[].length + 2\n     */\n    private static byte[] decodeByteArray(ByteBuf buffer) {\n        int size = decodeMsbLsb(buffer);\n        byte[] bytes = new byte[size];\n        buffer.readBytes(bytes);\n        return bytes;\n    }\n\n    // packing utils to reduce the amount of garbage while decoding ints\n    private static long packInts(int a, int b) {\n        return (((long) a) << 32) | (b & 0xFFFFFFFFL);\n    }\n\n    private static int unpackA(long ints) {\n        return (int) (ints >> 32);\n    }\n\n    private static int unpackB(long ints) {\n        return (int) ints;\n    }\n\n    /**\n     *  numberOfBytesConsumed = 2. return decoded result.\n     */\n    private static int decodeMsbLsb(ByteBuf buffer) {\n        int min = 0;\n        int max = 65535;\n        short msbSize = buffer.readUnsignedByte();\n        short lsbSize = buffer.readUnsignedByte();\n        int result = msbSize << 8 | lsbSize;\n        if (result < min || result > max) {\n            result = -1;\n        }\n        return result;\n    }\n\n    /**\n     * See 1.5.5 Variable Byte Integer section of MQTT 5.0 specification for encoding/decoding rules\n     *\n     * @param buffer the buffer to decode from\n     * @return result pack with a = decoded integer, b = numberOfBytesConsumed. Need to unpack to read them.\n     * @throws DecoderException if bad MQTT protocol limits Remaining Length\n     */\n    private static long decodeVariableByteInteger(ByteBuf buffer) {\n        int remainingLength = 0;\n        int multiplier = 1;\n        short digit;\n        int loops = 0;\n        do {\n            digit = buffer.readUnsignedByte();\n            remainingLength += (digit & 127) * multiplier;\n            multiplier *= 128;\n            loops++;\n        } while ((digit & 128) != 0 && loops < 4);\n\n        if (loops == 4 && (digit & 128) != 0) {\n            throw new DecoderException(\"MQTT protocol limits Remaining Length to 4 bytes\");\n        }\n        return packInts(remainingLength, loops);\n    }\n\n    private static final class Result<T> {\n\n        private final T value;\n        private final int numberOfBytesConsumed;\n\n        Result(T value, int numberOfBytesConsumed) {\n            this.value = value;\n            this.numberOfBytesConsumed = numberOfBytesConsumed;\n        }\n    }\n\n    private static Result<MqttProperties> decodeProperties(ByteBuf buffer) {\n        final long propertiesLength = decodeVariableByteInteger(buffer);\n        int totalPropertiesLength = unpackA(propertiesLength);\n        int numberOfBytesConsumed = unpackB(propertiesLength);\n\n        MqttProperties decodedProperties = new MqttProperties();\n        while (numberOfBytesConsumed < totalPropertiesLength) {\n            long propertyId = decodeVariableByteInteger(buffer);\n            final int propertyIdValue = unpackA(propertyId);\n            numberOfBytesConsumed += unpackB(propertyId);\n            MqttProperties.MqttPropertyType propertyType = MqttProperties.MqttPropertyType.valueOf(propertyIdValue);\n            switch (propertyType) {\n                case PAYLOAD_FORMAT_INDICATOR:\n                case REQUEST_PROBLEM_INFORMATION:\n                case REQUEST_RESPONSE_INFORMATION:\n                case MAXIMUM_QOS:\n                case RETAIN_AVAILABLE:\n                case WILDCARD_SUBSCRIPTION_AVAILABLE:\n                case SUBSCRIPTION_IDENTIFIER_AVAILABLE:\n                case SHARED_SUBSCRIPTION_AVAILABLE:\n                    final int b1 = buffer.readUnsignedByte();\n                    numberOfBytesConsumed++;\n                    decodedProperties.add(new MqttProperties.IntegerProperty(propertyIdValue, b1));\n                    break;\n                case SERVER_KEEP_ALIVE:\n                case RECEIVE_MAXIMUM:\n                case TOPIC_ALIAS_MAXIMUM:\n                case TOPIC_ALIAS:\n                    final int int2BytesResult = decodeMsbLsb(buffer);\n                    numberOfBytesConsumed += 2;\n                    decodedProperties.add(new MqttProperties.IntegerProperty(propertyIdValue, int2BytesResult));\n                    break;\n                case PUBLICATION_EXPIRY_INTERVAL:\n                case SESSION_EXPIRY_INTERVAL:\n                case WILL_DELAY_INTERVAL:\n                case MAXIMUM_PACKET_SIZE:\n                    final int maxPacketSize = buffer.readInt();\n                    numberOfBytesConsumed += 4;\n                    decodedProperties.add(new MqttProperties.IntegerProperty(propertyIdValue, maxPacketSize));\n                    break;\n                case SUBSCRIPTION_IDENTIFIER:\n                    long vbIntegerResult = decodeVariableByteInteger(buffer);\n                    numberOfBytesConsumed += unpackB(vbIntegerResult);\n                    decodedProperties.add(new MqttProperties.IntegerProperty(propertyIdValue, unpackA(vbIntegerResult)));\n                    break;\n                case CONTENT_TYPE:\n                case RESPONSE_TOPIC:\n                case ASSIGNED_CLIENT_IDENTIFIER:\n                case AUTHENTICATION_METHOD:\n                case RESPONSE_INFORMATION:\n                case SERVER_REFERENCE:\n                case REASON_STRING:\n                    final Result<String> stringResult = decodeString(buffer);\n                    numberOfBytesConsumed += stringResult.numberOfBytesConsumed;\n                    decodedProperties.add(new MqttProperties.StringProperty(propertyIdValue, stringResult.value));\n                    break;\n                case USER_PROPERTY:\n                    final Result<String> keyResult = decodeString(buffer);\n                    final Result<String> valueResult = decodeString(buffer);\n                    numberOfBytesConsumed += keyResult.numberOfBytesConsumed;\n                    numberOfBytesConsumed += valueResult.numberOfBytesConsumed;\n                    decodedProperties.add(new MqttProperties.UserProperty(keyResult.value, valueResult.value));\n                    break;\n                case CORRELATION_DATA:\n                case AUTHENTICATION_DATA:\n                    final byte[] binaryDataResult = decodeByteArray(buffer);\n                    numberOfBytesConsumed += binaryDataResult.length + 2;\n                    decodedProperties.add(new MqttProperties.BinaryProperty(propertyIdValue, binaryDataResult));\n                    break;\n                default:\n                    //shouldn't reach here\n                    throw new DecoderException(\"Unknown property type: \" + propertyType);\n            }\n        }\n\n        return new Result<MqttProperties>(decodedProperties, numberOfBytesConsumed);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttEncoder.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.ByteBufAllocator;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.ChannelHandler;\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.EncoderException;\nimport io.netty.handler.codec.MessageToMessageEncoder;\nimport io.netty.util.internal.EmptyArrays;\n\nimport java.util.List;\n\nimport static io.netty.buffer.ByteBufUtil.*;\n\n/**\n * Encodes Mqtt messages into bytes following the protocol specification v3.1\n * as described here <a href=\"https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html\">MQTTV3.1</a>\n * or v5.0 as described here <a href=\"https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html\">MQTTv5.0</a> -\n * depending on the version specified in the first CONNECT message that goes through the channel.\n */\n@ChannelHandler.Sharable\npublic final class MqttEncoder extends MessageToMessageEncoder<MqttMessage> {\n\n    public static final MqttEncoder INSTANCE = new MqttEncoder();\n\n    private MqttEncoder() { }\n\n    @Override\n    protected void encode(ChannelHandlerContext ctx, MqttMessage msg, List<Object> out) throws Exception {\n        out.add(doEncode(ctx, msg));\n    }\n\n    /**\n     * This is the main encoding method.\n     * It's only visible for testing.\n     *\n     * @param message MQTT message to encode\n     * @return ByteBuf with encoded bytes\n     */\n    static ByteBuf doEncode(ChannelHandlerContext ctx,\n                     MqttMessage message) {\n\n        switch (message.fixedHeader().messageType()) {\n            case CONNECT:\n                return encodeConnectMessage(ctx, (MqttConnectMessage) message);\n\n            case CONNACK:\n                return encodeConnAckMessage(ctx, (MqttConnAckMessage) message);\n\n            case PUBLISH:\n                return encodePublishMessage(ctx, (MqttPublishMessage) message);\n\n            case SUBSCRIBE:\n                return encodeSubscribeMessage(ctx, (MqttSubscribeMessage) message);\n\n            case UNSUBSCRIBE:\n                return encodeUnsubscribeMessage(ctx,  (MqttUnsubscribeMessage) message);\n\n            case SUBACK:\n                return encodeSubAckMessage(ctx, (MqttSubAckMessage) message);\n\n            case UNSUBACK:\n                if (message instanceof MqttUnsubAckMessage) {\n                    return encodeUnsubAckMessage(ctx, (MqttUnsubAckMessage) message);\n                }\n                return encodeMessageWithOnlySingleByteFixedHeaderAndMessageId(ctx.alloc(), message);\n\n            case PUBACK:\n            case PUBREC:\n            case PUBREL:\n            case PUBCOMP:\n                return encodePubReplyMessage(ctx, message);\n\n            case DISCONNECT:\n            case AUTH:\n                return encodeReasonCodePlusPropertiesMessage(ctx, message);\n\n            case PINGREQ:\n            case PINGRESP:\n                return encodeMessageWithOnlySingleByteFixedHeader(ctx.alloc(), message);\n\n            default:\n                throw new IllegalArgumentException(\n                        \"Unknown message type: \" + message.fixedHeader().messageType().value());\n        }\n    }\n\n    private static ByteBuf encodeConnectMessage(\n            ChannelHandlerContext ctx,\n            MqttConnectMessage message) {\n        int payloadBufferSize = 0;\n\n        MqttFixedHeader mqttFixedHeader = message.fixedHeader();\n        MqttConnectVariableHeader variableHeader = message.variableHeader();\n        MqttConnectPayload payload = message.payload();\n        MqttVersion mqttVersion = MqttVersion.fromProtocolNameAndLevel(variableHeader.name(),\n                (byte) variableHeader.version());\n        MqttCodecUtil.setMqttVersion(ctx, mqttVersion);\n\n        // as MQTT 3.1 & 3.1.1 spec, If the User Name Flag is set to 0, the Password Flag MUST be set to 0\n        if (!variableHeader.hasUserName() && variableHeader.hasPassword()) {\n            throw new EncoderException(\"Without a username, the password MUST be not set\");\n        }\n\n        // Client id\n        String clientIdentifier = payload.clientIdentifier();\n        if (!MqttCodecUtil.isValidClientId(mqttVersion, MqttConstant.DEFAULT_MAX_CLIENT_ID_LENGTH, clientIdentifier)) {\n            throw new MqttIdentifierRejectedException(\"invalid clientIdentifier: \" + clientIdentifier);\n        }\n        int clientIdentifierBytes = utf8Bytes(clientIdentifier);\n        payloadBufferSize += 2 + clientIdentifierBytes;\n\n        // Will topic and message\n        String willTopic = payload.willTopic();\n        int willTopicBytes = nullableUtf8Bytes(willTopic);\n        byte[] willMessage = payload.willMessageInBytes();\n        byte[] willMessageBytes = willMessage != null ? willMessage : EmptyArrays.EMPTY_BYTES;\n        if (variableHeader.isWillFlag()) {\n            payloadBufferSize += 2 + willTopicBytes;\n            payloadBufferSize += 2 + willMessageBytes.length;\n        }\n\n        String userName = payload.userName();\n        int userNameBytes = nullableUtf8Bytes(userName);\n        if (variableHeader.hasUserName()) {\n            payloadBufferSize += 2 + userNameBytes;\n        }\n\n        byte[] password = payload.passwordInBytes();\n        byte[] passwordBytes = password != null ? password : EmptyArrays.EMPTY_BYTES;\n        if (variableHeader.hasPassword()) {\n            payloadBufferSize += 2 + passwordBytes.length;\n        }\n\n        // Fixed and variable header\n        byte[] protocolNameBytes = mqttVersion.protocolNameBytes();\n        ByteBuf propertiesBuf = encodePropertiesIfNeeded(\n                mqttVersion,\n                ctx.alloc(),\n                message.variableHeader().properties());\n        try {\n            final ByteBuf willPropertiesBuf;\n            if (variableHeader.isWillFlag()) {\n                willPropertiesBuf = encodePropertiesIfNeeded(mqttVersion, ctx.alloc(), payload.willProperties());\n                payloadBufferSize += willPropertiesBuf.readableBytes();\n            } else {\n                willPropertiesBuf = Unpooled.EMPTY_BUFFER;\n            }\n            try {\n                int variableHeaderBufferSize = 2 + protocolNameBytes.length + 4 + propertiesBuf.readableBytes();\n\n                int variablePartSize = variableHeaderBufferSize + payloadBufferSize;\n                int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize);\n                ByteBuf buf = ctx.alloc().buffer(fixedHeaderBufferSize + variablePartSize);\n                buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));\n                writeVariableLengthInt(buf, variablePartSize);\n\n                buf.writeShort(protocolNameBytes.length);\n                buf.writeBytes(protocolNameBytes);\n\n                buf.writeByte(variableHeader.version());\n                buf.writeByte(getConnVariableHeaderFlag(variableHeader));\n                buf.writeShort(variableHeader.keepAliveTimeSeconds());\n                buf.writeBytes(propertiesBuf);\n\n                // Payload\n                writeExactUTF8String(buf, clientIdentifier, clientIdentifierBytes);\n                if (variableHeader.isWillFlag()) {\n                    buf.writeBytes(willPropertiesBuf);\n                    writeExactUTF8String(buf, willTopic, willTopicBytes);\n                    buf.writeShort(willMessageBytes.length);\n                    buf.writeBytes(willMessageBytes, 0, willMessageBytes.length);\n                }\n                if (variableHeader.hasUserName()) {\n                    writeExactUTF8String(buf, userName, userNameBytes);\n                }\n                if (variableHeader.hasPassword()) {\n                    buf.writeShort(passwordBytes.length);\n                    buf.writeBytes(passwordBytes, 0, passwordBytes.length);\n                }\n                return buf;\n            } finally {\n                willPropertiesBuf.release();\n            }\n        } finally {\n            propertiesBuf.release();\n        }\n    }\n\n    private static int getConnVariableHeaderFlag(MqttConnectVariableHeader variableHeader) {\n        int flagByte = 0;\n        if (variableHeader.hasUserName()) {\n            flagByte |= 0x80;\n        }\n        if (variableHeader.hasPassword()) {\n            flagByte |= 0x40;\n        }\n        if (variableHeader.isWillRetain()) {\n            flagByte |= 0x20;\n        }\n        flagByte |= (variableHeader.willQos() & 0x03) << 3;\n        if (variableHeader.isWillFlag()) {\n            flagByte |= 0x04;\n        }\n        if (variableHeader.isCleanSession()) {\n            flagByte |= 0x02;\n        }\n        return flagByte;\n    }\n\n    private static ByteBuf encodeConnAckMessage(\n            ChannelHandlerContext ctx,\n            MqttConnAckMessage message) {\n        final MqttVersion mqttVersion = MqttCodecUtil.getMqttVersion(ctx);\n        ByteBuf propertiesBuf = encodePropertiesIfNeeded(mqttVersion,\n                ctx.alloc(),\n                message.variableHeader().properties());\n\n        try {\n            int length = 4;\n            MqttConnectAckPayload payload = null;\n            if (message.payload() != null) {\n                payload = (MqttConnectAckPayload)message.payload();\n                if (payload.getData() != null && payload.getData().length > 0) {\n                    length += payload.getData().length;\n                }\n            }\n            ByteBuf buf = ctx.alloc().buffer(length + propertiesBuf.readableBytes());\n            buf.writeByte(getFixedHeaderByte1(message.fixedHeader()));\n            writeVariableLengthInt(buf, length - 2 + propertiesBuf.readableBytes());\n            buf.writeByte(message.variableHeader().isSessionPresent() ? 0x01 : 0x00);\n            buf.writeByte(message.variableHeader().connectReturnCode().byteValue());\n            if (length > 4) {\n                buf.writeBytes(payload.getData());\n            }\n            buf.writeBytes(propertiesBuf);\n            return buf;\n        } finally {\n            propertiesBuf.release();\n        }\n    }\n\n    private static ByteBuf encodeSubscribeMessage(\n            ChannelHandlerContext ctx,\n            MqttSubscribeMessage message) {\n        MqttVersion mqttVersion = MqttCodecUtil.getMqttVersion(ctx);\n        ByteBuf propertiesBuf = encodePropertiesIfNeeded(mqttVersion,\n                ctx.alloc(),\n                message.idAndPropertiesVariableHeader().properties());\n\n        try {\n            final int variableHeaderBufferSize = 2 + propertiesBuf.readableBytes();\n            int payloadBufferSize = 0;\n\n            MqttFixedHeader mqttFixedHeader = message.fixedHeader();\n            MqttMessageIdVariableHeader variableHeader = message.variableHeader();\n            MqttSubscribePayload payload = message.payload();\n\n            for (MqttTopicSubscription topic : payload.topicSubscriptions()) {\n                String topicName = topic.topicName();\n                int topicNameBytes = utf8Bytes(topicName);\n                payloadBufferSize += 2 + topicNameBytes;\n                payloadBufferSize += 1;\n            }\n\n            int variablePartSize = variableHeaderBufferSize + payloadBufferSize;\n            int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize);\n\n            ByteBuf buf = ctx.alloc().buffer(fixedHeaderBufferSize + variablePartSize);\n            buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));\n            writeVariableLengthInt(buf, variablePartSize);\n\n            // Variable Header\n            int messageId = variableHeader.messageId();\n            buf.writeShort(messageId);\n            buf.writeBytes(propertiesBuf);\n\n            // Payload\n            for (MqttTopicSubscription topic : payload.topicSubscriptions()) {\n                writeUnsafeUTF8String(buf, topic.topicName());\n                if (mqttVersion.protocolLevel() >= MqttVersion.MQTT_3_1_1.protocolLevel()) {\n                    buf.writeByte(topic.qualityOfService().value());\n                } else {\n                    final MqttSubscriptionOption option = topic.option();\n\n                    int optionEncoded = option.retainHandling().value() << 4;\n                    if (option.isRetainAsPublished()) {\n                        optionEncoded |= 0x08;\n                    }\n                    if (option.isNoLocal()) {\n                        optionEncoded |= 0x04;\n                    }\n                    optionEncoded |= option.qos().value();\n\n                    buf.writeByte(optionEncoded);\n                }\n            }\n\n            return buf;\n        } finally {\n            propertiesBuf.release();\n        }\n    }\n\n    private static ByteBuf encodeUnsubscribeMessage(\n            ChannelHandlerContext ctx,\n            MqttUnsubscribeMessage message) {\n        MqttVersion mqttVersion = MqttCodecUtil.getMqttVersion(ctx);\n        ByteBuf propertiesBuf = encodePropertiesIfNeeded(mqttVersion,\n                ctx.alloc(),\n                message.idAndPropertiesVariableHeader().properties());\n\n        try {\n            final int variableHeaderBufferSize = 2 + propertiesBuf.readableBytes();\n            int payloadBufferSize = 0;\n\n            MqttFixedHeader mqttFixedHeader = message.fixedHeader();\n            MqttMessageIdVariableHeader variableHeader = message.variableHeader();\n            MqttUnsubscribePayload payload = message.payload();\n\n            for (String topicName : payload.topics()) {\n                int topicNameBytes = utf8Bytes(topicName);\n                payloadBufferSize += 2 + topicNameBytes;\n            }\n\n            int variablePartSize = variableHeaderBufferSize + payloadBufferSize;\n            int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize);\n\n            ByteBuf buf = ctx.alloc().buffer(fixedHeaderBufferSize + variablePartSize);\n            buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));\n            writeVariableLengthInt(buf, variablePartSize);\n\n            // Variable Header\n            int messageId = variableHeader.messageId();\n            buf.writeShort(messageId);\n            buf.writeBytes(propertiesBuf);\n\n            // Payload\n            for (String topicName : payload.topics()) {\n                writeUnsafeUTF8String(buf, topicName);\n            }\n\n            return buf;\n        } finally {\n            propertiesBuf.release();\n        }\n    }\n\n    private static ByteBuf encodeSubAckMessage(\n            ChannelHandlerContext ctx,\n            MqttSubAckMessage message) {\n        MqttVersion mqttVersion = MqttCodecUtil.getMqttVersion(ctx);\n        ByteBuf propertiesBuf = encodePropertiesIfNeeded(mqttVersion,\n                ctx.alloc(),\n                message.idAndPropertiesVariableHeader().properties());\n        try {\n            int variableHeaderBufferSize = 2 + propertiesBuf.readableBytes();\n            int payloadBufferSize = message.payload().grantedQoSLevels().size();\n            int variablePartSize = variableHeaderBufferSize + payloadBufferSize;\n            int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize);\n            ByteBuf buf = ctx.alloc().buffer(fixedHeaderBufferSize + variablePartSize);\n            buf.writeByte(getFixedHeaderByte1(message.fixedHeader()));\n            writeVariableLengthInt(buf, variablePartSize);\n            buf.writeShort(message.variableHeader().messageId());\n            buf.writeBytes(propertiesBuf);\n            for (int code: message.payload().reasonCodes()) {\n                buf.writeByte(code);\n            }\n\n            return buf;\n        } finally {\n            propertiesBuf.release();\n        }\n    }\n\n    private static ByteBuf encodeUnsubAckMessage(\n            ChannelHandlerContext ctx,\n            MqttUnsubAckMessage message) {\n        if (message.variableHeader() instanceof  MqttMessageIdAndPropertiesVariableHeader) {\n            MqttVersion mqttVersion = MqttCodecUtil.getMqttVersion(ctx);\n            ByteBuf propertiesBuf = encodePropertiesIfNeeded(mqttVersion,\n                    ctx.alloc(),\n                    message.idAndPropertiesVariableHeader().properties());\n            try {\n                int variableHeaderBufferSize = 2 + propertiesBuf.readableBytes();\n                MqttUnsubAckPayload payload = message.payload();\n                int payloadBufferSize = payload == null ? 0 : payload.unsubscribeReasonCodes().size();\n                int variablePartSize = variableHeaderBufferSize + payloadBufferSize;\n                int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize);\n                ByteBuf buf = ctx.alloc().buffer(fixedHeaderBufferSize + variablePartSize);\n                buf.writeByte(getFixedHeaderByte1(message.fixedHeader()));\n                writeVariableLengthInt(buf, variablePartSize);\n                buf.writeShort(message.variableHeader().messageId());\n                buf.writeBytes(propertiesBuf);\n\n                if (payload != null) {\n                    for (Short reasonCode : payload.unsubscribeReasonCodes()) {\n                        buf.writeByte(reasonCode);\n                    }\n                }\n\n                return buf;\n            } finally {\n                propertiesBuf.release();\n            }\n        } else {\n            return encodeMessageWithOnlySingleByteFixedHeaderAndMessageId(ctx.alloc(), message);\n        }\n    }\n\n    private static ByteBuf encodePublishMessage(\n            ChannelHandlerContext ctx,\n            MqttPublishMessage message) {\n        MqttVersion mqttVersion = MqttCodecUtil.getMqttVersion(ctx);\n        MqttFixedHeader mqttFixedHeader = message.fixedHeader();\n        MqttPublishVariableHeader variableHeader = message.variableHeader();\n        ByteBuf payload = message.payload().duplicate();\n\n        String topicName = variableHeader.topicName();\n        int topicNameBytes = utf8Bytes(topicName);\n\n        ByteBuf propertiesBuf = encodePropertiesIfNeeded(mqttVersion,\n                ctx.alloc(),\n                message.variableHeader().properties());\n\n        try {\n            int variableHeaderBufferSize = 2 + topicNameBytes +\n                    (mqttFixedHeader.qosLevel().value() > 0 ? 2 : 0) + propertiesBuf.readableBytes();\n            int payloadBufferSize = payload.readableBytes();\n            int variablePartSize = variableHeaderBufferSize + payloadBufferSize;\n            int fixedHeaderBufferSize = 1 + getVariableLengthInt(variablePartSize);\n\n            ByteBuf buf = ctx.alloc().buffer(fixedHeaderBufferSize + variablePartSize);\n            buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));\n            writeVariableLengthInt(buf, variablePartSize);\n            writeExactUTF8String(buf, topicName, topicNameBytes);\n            if (mqttFixedHeader.qosLevel().value() > 0) {\n                buf.writeShort(variableHeader.packetId());\n            }\n            buf.writeBytes(propertiesBuf);\n            buf.writeBytes(payload);\n\n            return buf;\n        } finally {\n            propertiesBuf.release();\n        }\n    }\n\n    private static ByteBuf encodePubReplyMessage(ChannelHandlerContext ctx,\n                                          MqttMessage message) {\n        if (message.variableHeader() instanceof MqttPubReplyMessageVariableHeader) {\n            MqttFixedHeader mqttFixedHeader = message.fixedHeader();\n            MqttPubReplyMessageVariableHeader variableHeader =\n                    (MqttPubReplyMessageVariableHeader) message.variableHeader();\n            int msgId = variableHeader.messageId();\n\n            final ByteBuf propertiesBuf;\n            final boolean includeReasonCode;\n            final int variableHeaderBufferSize;\n            final MqttVersion mqttVersion = MqttCodecUtil.getMqttVersion(ctx);\n            if (mqttVersion == MqttVersion.MQTT_5 &&\n                    (variableHeader.reasonCode() != MqttPubReplyMessageVariableHeader.REASON_CODE_OK ||\n                            !variableHeader.properties().isEmpty())) {\n                propertiesBuf = encodeProperties(ctx.alloc(), variableHeader.properties());\n                includeReasonCode = true;\n                variableHeaderBufferSize = 3 + propertiesBuf.readableBytes();\n            } else {\n                propertiesBuf = Unpooled.EMPTY_BUFFER;\n                includeReasonCode = false;\n                variableHeaderBufferSize = 2;\n            }\n\n            try {\n                final int fixedHeaderBufferSize = 1 + getVariableLengthInt(variableHeaderBufferSize);\n                ByteBuf buf = ctx.alloc().buffer(fixedHeaderBufferSize + variableHeaderBufferSize);\n                buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));\n                writeVariableLengthInt(buf, variableHeaderBufferSize);\n                buf.writeShort(msgId);\n                if (includeReasonCode) {\n                    buf.writeByte(variableHeader.reasonCode());\n                }\n                buf.writeBytes(propertiesBuf);\n\n                return buf;\n            } finally {\n                propertiesBuf.release();\n            }\n        } else {\n            return encodeMessageWithOnlySingleByteFixedHeaderAndMessageId(ctx.alloc(), message);\n        }\n    }\n\n    private static ByteBuf encodeMessageWithOnlySingleByteFixedHeaderAndMessageId(\n            ByteBufAllocator byteBufAllocator,\n            MqttMessage message) {\n        MqttFixedHeader mqttFixedHeader = message.fixedHeader();\n        MqttMessageIdVariableHeader variableHeader = (MqttMessageIdVariableHeader) message.variableHeader();\n        int msgId = variableHeader.messageId();\n\n        int variableHeaderBufferSize = 2; // variable part only has a message id\n        ByteBuf payload = null;\n        if (message.payload() != null) {\n        \tpayload = ((ByteBuf)message.payload()).duplicate();\n        \tvariableHeaderBufferSize += payload.readableBytes();\n\t\t    }\n        int fixedHeaderBufferSize = 1 + getVariableLengthInt(variableHeaderBufferSize);\n        ByteBuf buf = byteBufAllocator.buffer(fixedHeaderBufferSize + variableHeaderBufferSize);\n        buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));\n        writeVariableLengthInt(buf, variableHeaderBufferSize);\n        buf.writeShort(msgId);\n        if (payload != null) {\n        \tbuf.writeBytes(payload);\n\t\t    }\n        return buf;\n    }\n\n    private static ByteBuf encodeReasonCodePlusPropertiesMessage(\n            ChannelHandlerContext ctx,\n            MqttMessage message) {\n        if (message.variableHeader() instanceof MqttReasonCodeAndPropertiesVariableHeader) {\n            MqttVersion mqttVersion = MqttCodecUtil.getMqttVersion(ctx);\n            MqttFixedHeader mqttFixedHeader = message.fixedHeader();\n            MqttReasonCodeAndPropertiesVariableHeader variableHeader =\n                    (MqttReasonCodeAndPropertiesVariableHeader) message.variableHeader();\n\n            final ByteBuf propertiesBuf;\n            final boolean includeReasonCode;\n            final int variableHeaderBufferSize;\n            if (mqttVersion == MqttVersion.MQTT_5 &&\n                    (variableHeader.reasonCode() != MqttReasonCodeAndPropertiesVariableHeader.REASON_CODE_OK ||\n                            !variableHeader.properties().isEmpty())) {\n                propertiesBuf = encodeProperties(ctx.alloc(), variableHeader.properties());\n                includeReasonCode = true;\n                variableHeaderBufferSize = 1 + propertiesBuf.readableBytes();\n            } else {\n                propertiesBuf = Unpooled.EMPTY_BUFFER;\n                includeReasonCode = false;\n                variableHeaderBufferSize = 0;\n            }\n\n            try {\n                final int fixedHeaderBufferSize = 1 + getVariableLengthInt(variableHeaderBufferSize);\n                ByteBuf buf = ctx.alloc().buffer(fixedHeaderBufferSize + variableHeaderBufferSize);\n                buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));\n                writeVariableLengthInt(buf, variableHeaderBufferSize);\n                if (includeReasonCode) {\n                    buf.writeByte(variableHeader.reasonCode());\n                }\n                buf.writeBytes(propertiesBuf);\n\n                return buf;\n            } finally {\n                propertiesBuf.release();\n            }\n        } else {\n            return encodeMessageWithOnlySingleByteFixedHeader(ctx.alloc(), message);\n        }\n    }\n\n    private static ByteBuf encodeMessageWithOnlySingleByteFixedHeader(\n            ByteBufAllocator byteBufAllocator,\n            MqttMessage message) {\n        MqttFixedHeader mqttFixedHeader = message.fixedHeader();\n        ByteBuf buf = byteBufAllocator.buffer(2);\n        buf.writeByte(getFixedHeaderByte1(mqttFixedHeader));\n        buf.writeByte(0);\n\n        return buf;\n    }\n\n    private static ByteBuf encodePropertiesIfNeeded(MqttVersion mqttVersion,\n                                             ByteBufAllocator byteBufAllocator,\n                                             MqttProperties mqttProperties) {\n        if (mqttVersion == MqttVersion.MQTT_5) {\n            return encodeProperties(byteBufAllocator, mqttProperties);\n        }\n        return Unpooled.EMPTY_BUFFER;\n    }\n\n    private static ByteBuf encodeProperties(ByteBufAllocator byteBufAllocator,\n                                            MqttProperties mqttProperties) {\n        ByteBuf propertiesHeaderBuf = byteBufAllocator.buffer();\n        // encode also the Properties part\n        try {\n            ByteBuf propertiesBuf = byteBufAllocator.buffer();\n            try {\n                for (MqttProperties.MqttProperty property : mqttProperties.listAll()) {\n                    MqttProperties.MqttPropertyType propertyType =\n                            MqttProperties.MqttPropertyType.valueOf(property.propertyId);\n                    switch (propertyType) {\n                        case PAYLOAD_FORMAT_INDICATOR:\n                        case REQUEST_PROBLEM_INFORMATION:\n                        case REQUEST_RESPONSE_INFORMATION:\n                        case MAXIMUM_QOS:\n                        case RETAIN_AVAILABLE:\n                        case WILDCARD_SUBSCRIPTION_AVAILABLE:\n                        case SUBSCRIPTION_IDENTIFIER_AVAILABLE:\n                        case SHARED_SUBSCRIPTION_AVAILABLE:\n                            writeVariableLengthInt(propertiesBuf, property.propertyId);\n                            final byte bytePropValue = ((MqttProperties.IntegerProperty) property).value.byteValue();\n                            propertiesBuf.writeByte(bytePropValue);\n                            break;\n                        case SERVER_KEEP_ALIVE:\n                        case RECEIVE_MAXIMUM:\n                        case TOPIC_ALIAS_MAXIMUM:\n                        case TOPIC_ALIAS:\n                            writeVariableLengthInt(propertiesBuf, property.propertyId);\n                            final short twoBytesInPropValue =\n                                    ((MqttProperties.IntegerProperty) property).value.shortValue();\n                            propertiesBuf.writeShort(twoBytesInPropValue);\n                            break;\n                        case PUBLICATION_EXPIRY_INTERVAL:\n                        case SESSION_EXPIRY_INTERVAL:\n                        case WILL_DELAY_INTERVAL:\n                        case MAXIMUM_PACKET_SIZE:\n                            writeVariableLengthInt(propertiesBuf, property.propertyId);\n                            final int fourBytesIntPropValue = ((MqttProperties.IntegerProperty) property).value;\n                            propertiesBuf.writeInt(fourBytesIntPropValue);\n                            break;\n                        case SUBSCRIPTION_IDENTIFIER:\n                            writeVariableLengthInt(propertiesBuf, property.propertyId);\n                            final int vbi = ((MqttProperties.IntegerProperty) property).value;\n                            writeVariableLengthInt(propertiesBuf, vbi);\n                            break;\n                        case CONTENT_TYPE:\n                        case RESPONSE_TOPIC:\n                        case ASSIGNED_CLIENT_IDENTIFIER:\n                        case AUTHENTICATION_METHOD:\n                        case RESPONSE_INFORMATION:\n                        case SERVER_REFERENCE:\n                        case REASON_STRING:\n                            writeVariableLengthInt(propertiesBuf, property.propertyId);\n                            writeEagerUTF8String(propertiesBuf, ((MqttProperties.StringProperty) property).value);\n                            break;\n                        case USER_PROPERTY:\n                            final List<MqttProperties.StringPair> pairs =\n                                    ((MqttProperties.UserProperties) property).value;\n                            for (MqttProperties.StringPair pair : pairs) {\n                                writeVariableLengthInt(propertiesBuf, property.propertyId);\n                                writeEagerUTF8String(propertiesBuf, pair.key);\n                                writeEagerUTF8String(propertiesBuf, pair.value);\n                            }\n                            break;\n                        case CORRELATION_DATA:\n                        case AUTHENTICATION_DATA:\n                            writeVariableLengthInt(propertiesBuf, property.propertyId);\n                            final byte[] binaryPropValue = ((MqttProperties.BinaryProperty) property).value;\n                            propertiesBuf.writeShort(binaryPropValue.length);\n                            propertiesBuf.writeBytes(binaryPropValue, 0, binaryPropValue.length);\n                            break;\n                        default:\n                            //shouldn't reach here\n                            throw new EncoderException(\"Unknown property type: \" + propertyType);\n                    }\n                }\n                writeVariableLengthInt(propertiesHeaderBuf, propertiesBuf.readableBytes());\n                propertiesHeaderBuf.writeBytes(propertiesBuf);\n\n                return propertiesHeaderBuf;\n            } finally {\n                propertiesBuf.release();\n            }\n        } catch (RuntimeException e) {\n            propertiesHeaderBuf.release();\n            throw e;\n        }\n    }\n\n    private static int getFixedHeaderByte1(MqttFixedHeader header) {\n        int ret = 0;\n        ret |= header.messageType().value() << 4;\n        if (header.isDup()) {\n            ret |= 0x08;\n        }\n        ret |= header.qosLevel().value() << 1;\n        if (header.isRetain()) {\n            ret |= 0x01;\n        }\n        return ret;\n    }\n\n    private static void writeVariableLengthInt(ByteBuf buf, int num) {\n        do {\n            int digit = num % 128;\n            num /= 128;\n            if (num > 0) {\n                digit |= 0x80;\n            }\n            buf.writeByte(digit);\n        } while (num > 0);\n    }\n\n    private static int nullableUtf8Bytes(String s) {\n        return s == null? 0 : utf8Bytes(s);\n    }\n\n    private static int nullableMaxUtf8Bytes(String s) {\n        return s == null? 0 : utf8MaxBytes(s);\n    }\n\n    private static void writeExactUTF8String(ByteBuf buf, String s, int utf8Length) {\n        buf.ensureWritable(utf8Length + 2);\n        buf.writeShort(utf8Length);\n        if (utf8Length > 0) {\n            final int writtenUtf8Length = reserveAndWriteUtf8(buf, s, utf8Length);\n            assert writtenUtf8Length == utf8Length;\n        }\n    }\n\n    private static void writeEagerUTF8String(ByteBuf buf, String s) {\n        final int maxUtf8Length = nullableMaxUtf8Bytes(s);\n        buf.ensureWritable(maxUtf8Length + 2);\n        final int writerIndex = buf.writerIndex();\n        final int startUtf8String = writerIndex + 2;\n        buf.writerIndex(startUtf8String);\n        final int utf8Length = s != null? reserveAndWriteUtf8(buf, s, maxUtf8Length) : 0;\n        buf.setShort(writerIndex, utf8Length);\n    }\n\n    private static void writeUnsafeUTF8String(ByteBuf buf, String s) {\n        final int writerIndex = buf.writerIndex();\n        final int startUtf8String = writerIndex + 2;\n        // no need to reserve any capacity here, already done earlier: that's why is Unsafe\n        buf.writerIndex(startUtf8String);\n        final int utf8Length = s != null? reserveAndWriteUtf8(buf, s, 0) : 0;\n        buf.setShort(writerIndex, utf8Length);\n    }\n\n    private static int getVariableLengthInt(int num) {\n        int count = 0;\n        do {\n            num /= 128;\n            count++;\n        } while (num > 0);\n        return count;\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttFixedHeader.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.ObjectUtil;\nimport io.netty.util.internal.StringUtil;\n\n/**\n * See <a href=\"https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#fixed-header\">\n *     MQTTV3.1/fixed-header</a>\n */\npublic final class MqttFixedHeader {\n\n    private final MqttMessageType messageType;\n    private final boolean isDup;\n    private final MqttQoS qosLevel;\n    private final boolean isRetain;\n    private final int remainingLength;\n\n    public MqttFixedHeader(\n            MqttMessageType messageType,\n            boolean isDup,\n            MqttQoS qosLevel,\n            boolean isRetain,\n            int remainingLength) {\n        this.messageType = ObjectUtil.checkNotNull(messageType, \"messageType\");\n        this.isDup = isDup;\n        this.qosLevel = ObjectUtil.checkNotNull(qosLevel, \"qosLevel\");\n        this.isRetain = isRetain;\n        this.remainingLength = remainingLength;\n    }\n\n    public MqttMessageType messageType() {\n        return messageType;\n    }\n\n    public boolean isDup() {\n        return isDup;\n    }\n\n    public MqttQoS qosLevel() {\n        return qosLevel;\n    }\n\n    public boolean isRetain() {\n        return isRetain;\n    }\n\n    public int remainingLength() {\n        return remainingLength;\n    }\n\n    @Override\n    public String toString() {\n        return new StringBuilder(StringUtil.simpleClassName(this))\n            .append('[')\n            .append(\"messageType=\").append(messageType)\n            .append(\", isDup=\").append(isDup)\n            .append(\", qosLevel=\").append(qosLevel)\n            .append(\", isRetain=\").append(isRetain)\n            .append(\", remainingLength=\").append(remainingLength)\n            .append(']')\n            .toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttIdentifierRejectedException.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.handler.codec.DecoderException;\n\n/**\n * A {@link MqttIdentifierRejectedException} which is thrown when a CONNECT request contains invalid client identifier.\n */\npublic final class MqttIdentifierRejectedException extends DecoderException {\n\n    private static final long serialVersionUID = -1323503322689614981L;\n\n    /**\n     * Creates a new instance\n     */\n    public MqttIdentifierRejectedException() { }\n\n    /**\n     * Creates a new instance\n     */\n    public MqttIdentifierRejectedException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Creates a new instance\n     */\n    public MqttIdentifierRejectedException(String message) {\n        super(message);\n    }\n\n    /**\n     * Creates a new instance\n     */\n    public MqttIdentifierRejectedException(Throwable cause) {\n        super(cause);\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttMessage.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.handler.codec.DecoderResult;\nimport io.netty.util.internal.StringUtil;\n\n/**\n * Base class for all MQTT message types.\n */\npublic class MqttMessage {\n\n    private final MqttFixedHeader mqttFixedHeader;\n    private final Object variableHeader;\n    private final Object payload;\n    private final DecoderResult decoderResult;\n\n    // Constants for fixed-header only message types with all flags set to 0 (see\n    // https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Table_2.2_-)\n    public static final MqttMessage PINGREQ = new MqttMessage(new MqttFixedHeader(MqttMessageType.PINGREQ, false,\n            MqttQoS.AT_MOST_ONCE, false, 0));\n\n    public static final MqttMessage PINGRESP = new MqttMessage(new MqttFixedHeader(MqttMessageType.PINGRESP, false,\n            MqttQoS.AT_MOST_ONCE, false, 0));\n\n    public static final MqttMessage DISCONNECT = new MqttMessage(new MqttFixedHeader(MqttMessageType.DISCONNECT, false,\n            MqttQoS.AT_MOST_ONCE, false, 0));\n\n    public MqttMessage(MqttFixedHeader mqttFixedHeader) {\n        this(mqttFixedHeader, null, null);\n    }\n\n    public MqttMessage(MqttFixedHeader mqttFixedHeader, Object variableHeader) {\n        this(mqttFixedHeader, variableHeader, null);\n    }\n\n    public MqttMessage(MqttFixedHeader mqttFixedHeader, Object variableHeader, Object payload) {\n        this(mqttFixedHeader, variableHeader, payload, DecoderResult.SUCCESS);\n    }\n\n    public MqttMessage(\n            MqttFixedHeader mqttFixedHeader,\n            Object variableHeader,\n            Object payload,\n            DecoderResult decoderResult) {\n        this.mqttFixedHeader = mqttFixedHeader;\n        this.variableHeader = variableHeader;\n        this.payload = payload;\n        this.decoderResult = decoderResult;\n    }\n\n    public MqttFixedHeader fixedHeader() {\n        return mqttFixedHeader;\n    }\n\n    public Object variableHeader() {\n        return variableHeader;\n    }\n\n    public Object payload() {\n        return payload;\n    }\n\n    public DecoderResult decoderResult() {\n        return decoderResult;\n    }\n\n    @Override\n    public String toString() {\n        return new StringBuilder(StringUtil.simpleClassName(this))\n            .append('[')\n            .append(\"fixedHeader=\").append(fixedHeader() != null ? fixedHeader().toString() : \"\")\n            .append(\", variableHeader=\").append(variableHeader() != null ? variableHeader.toString() : \"\")\n            .append(\", payload=\").append(payload() != null ? payload.toString() : \"\")\n            .append(']')\n            .toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttMessageBuilders.java",
    "content": "/*\n * Copyright 2017 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage io.netty.handler.codec.mqtt;\n\nimport static io.netty.util.internal.ObjectUtil.checkPositive;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.util.CharsetUtil;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic final class MqttMessageBuilders {\n\n    public static final class PublishBuilder {\n        private String topic;\n        private boolean retained;\n        private MqttQoS qos;\n        private ByteBuf payload;\n        private int messageId;\n        private MqttProperties mqttProperties;\n\n        PublishBuilder() {\n        }\n\n        public PublishBuilder topicName(String topic) {\n            this.topic = topic;\n            return this;\n        }\n\n        public PublishBuilder retained(boolean retained) {\n            this.retained = retained;\n            return this;\n        }\n\n        public PublishBuilder qos(MqttQoS qos) {\n            this.qos = qos;\n            return this;\n        }\n\n        public PublishBuilder payload(ByteBuf payload) {\n            this.payload = payload;\n            return this;\n        }\n\n        public PublishBuilder messageId(int messageId) {\n            this.messageId = messageId;\n            return this;\n        }\n\n        public PublishBuilder properties(MqttProperties properties) {\n            this.mqttProperties = properties;\n            return this;\n        }\n\n        public MqttPublishMessage build() {\n            MqttFixedHeader mqttFixedHeader = new MqttFixedHeader(MqttMessageType.PUBLISH, false, qos, retained, 0);\n            MqttPublishVariableHeader mqttVariableHeader =\n                    new MqttPublishVariableHeader(topic, messageId, mqttProperties);\n            return new MqttPublishMessage(mqttFixedHeader, mqttVariableHeader, Unpooled.buffer().writeBytes(payload));\n        }\n    }\n\n    public static final class ConnectBuilder {\n\n        private MqttVersion version = MqttVersion.MQTT_3_1_1;\n        private String clientId;\n        private boolean cleanSession;\n        private boolean hasUser;\n        private boolean hasPassword;\n        private int keepAliveSecs;\n        private MqttProperties willProperties = MqttProperties.NO_PROPERTIES;\n        private boolean willFlag;\n        private boolean willRetain;\n        private MqttQoS willQos = MqttQoS.AT_MOST_ONCE;\n        private String willTopic;\n        private byte[] willMessage;\n        private String username;\n        private byte[] password;\n        private MqttProperties properties = MqttProperties.NO_PROPERTIES;\n\n        ConnectBuilder() {\n        }\n\n        public ConnectBuilder protocolVersion(MqttVersion version) {\n            this.version = version;\n            return this;\n        }\n\n        public ConnectBuilder clientId(String clientId) {\n            this.clientId = clientId;\n            return this;\n        }\n\n        public ConnectBuilder cleanSession(boolean cleanSession) {\n            this.cleanSession = cleanSession;\n            return this;\n        }\n\n        public ConnectBuilder keepAlive(int keepAliveSecs) {\n            this.keepAliveSecs = keepAliveSecs;\n            return this;\n        }\n\n        public ConnectBuilder willFlag(boolean willFlag) {\n            this.willFlag = willFlag;\n            return this;\n        }\n\n        public ConnectBuilder willQoS(MqttQoS willQos) {\n            this.willQos = willQos;\n            return this;\n        }\n\n        public ConnectBuilder willTopic(String willTopic) {\n            this.willTopic = willTopic;\n            return this;\n        }\n\n        /**\n         * @deprecated use {@link ConnectBuilder#willMessage(byte[])} instead\n         */\n        @Deprecated\n        public ConnectBuilder willMessage(String willMessage) {\n            willMessage(willMessage == null ? null : willMessage.getBytes(CharsetUtil.UTF_8));\n            return this;\n        }\n\n        public ConnectBuilder willMessage(byte[] willMessage) {\n            this.willMessage = willMessage;\n            return this;\n        }\n\n        public ConnectBuilder willRetain(boolean willRetain) {\n            this.willRetain = willRetain;\n            return this;\n        }\n\n        public ConnectBuilder willProperties(MqttProperties willProperties) {\n            this.willProperties = willProperties;\n            return this;\n        }\n\n        public ConnectBuilder hasUser(boolean value) {\n            this.hasUser = value;\n            return this;\n        }\n\n        public ConnectBuilder hasPassword(boolean value) {\n            this.hasPassword = value;\n            return this;\n        }\n\n        public ConnectBuilder username(String username) {\n            this.hasUser = username != null;\n            this.username = username;\n            return this;\n        }\n\n        /**\n         * @deprecated use {@link ConnectBuilder#password(byte[])} instead\n         */\n        @Deprecated\n        public ConnectBuilder password(String password) {\n            password(password == null ? null : password.getBytes(CharsetUtil.UTF_8));\n            return this;\n        }\n\n        public ConnectBuilder password(byte[] password) {\n            this.hasPassword = password != null;\n            this.password = password;\n            return this;\n        }\n\n        public ConnectBuilder properties(MqttProperties properties) {\n            this.properties = properties;\n            return this;\n        }\n\n        public MqttConnectMessage build() {\n            MqttFixedHeader mqttFixedHeader =\n                    new MqttFixedHeader(MqttMessageType.CONNECT, false, MqttQoS.AT_MOST_ONCE, false, 0);\n            MqttConnectVariableHeader mqttConnectVariableHeader =\n                    new MqttConnectVariableHeader(\n                            version.protocolName(),\n                            version.protocolLevel(),\n                            hasUser,\n                            hasPassword,\n                            willRetain,\n                            willQos.value(),\n                            willFlag,\n                            cleanSession,\n                            keepAliveSecs,\n                            properties);\n            MqttConnectPayload mqttConnectPayload =\n                    new MqttConnectPayload(clientId, willProperties, willTopic, willMessage, username, password, null);\n            return new MqttConnectMessage(mqttFixedHeader, mqttConnectVariableHeader, mqttConnectPayload);\n        }\n    }\n\n    public static final class SubscribeBuilder {\n\n        private List<MqttTopicSubscription> subscriptions;\n        private int messageId;\n        private MqttProperties properties;\n\n        SubscribeBuilder() {\n        }\n\n        public SubscribeBuilder addSubscription(MqttQoS qos, String topic) {\n            ensureSubscriptionsExist();\n            subscriptions.add(new MqttTopicSubscription(topic, qos));\n            return this;\n        }\n\n        public SubscribeBuilder addSubscription(String topic, MqttSubscriptionOption option) {\n            ensureSubscriptionsExist();\n            subscriptions.add(new MqttTopicSubscription(topic, option));\n            return this;\n        }\n\n        public SubscribeBuilder messageId(int messageId) {\n            this.messageId = messageId;\n            return this;\n        }\n\n        public SubscribeBuilder properties(MqttProperties properties) {\n            this.properties = properties;\n            return this;\n        }\n\n        public MqttSubscribeMessage build() {\n            MqttFixedHeader mqttFixedHeader =\n                    new MqttFixedHeader(MqttMessageType.SUBSCRIBE, false, MqttQoS.AT_LEAST_ONCE, false, 0);\n            MqttMessageIdAndPropertiesVariableHeader mqttVariableHeader =\n                    new MqttMessageIdAndPropertiesVariableHeader(messageId, properties);\n            MqttSubscribePayload mqttSubscribePayload = new MqttSubscribePayload(subscriptions);\n            return new MqttSubscribeMessage(mqttFixedHeader, mqttVariableHeader, mqttSubscribePayload);\n        }\n\n        private void ensureSubscriptionsExist() {\n            if (subscriptions == null) {\n                subscriptions = new ArrayList<MqttTopicSubscription>(5);\n            }\n        }\n    }\n\n    public static final class UnsubscribeBuilder {\n\n        private List<String> topicFilters;\n        private int messageId;\n        private MqttProperties properties;\n\n        UnsubscribeBuilder() {\n        }\n\n        public UnsubscribeBuilder addTopicFilter(String topic) {\n            if (topicFilters == null) {\n                topicFilters = new ArrayList<String>(5);\n            }\n            topicFilters.add(topic);\n            return this;\n        }\n\n        public UnsubscribeBuilder messageId(int messageId) {\n            this.messageId = messageId;\n            return this;\n        }\n\n        public UnsubscribeBuilder properties(MqttProperties properties) {\n            this.properties = properties;\n            return this;\n        }\n\n        public MqttUnsubscribeMessage build() {\n            MqttFixedHeader mqttFixedHeader =\n                    new MqttFixedHeader(MqttMessageType.UNSUBSCRIBE, false, MqttQoS.AT_LEAST_ONCE, false, 0);\n            MqttMessageIdAndPropertiesVariableHeader mqttVariableHeader =\n                    new MqttMessageIdAndPropertiesVariableHeader(messageId, properties);\n            MqttUnsubscribePayload mqttSubscribePayload = new MqttUnsubscribePayload(topicFilters);\n            return new MqttUnsubscribeMessage(mqttFixedHeader, mqttVariableHeader, mqttSubscribePayload);\n        }\n    }\n\n    public interface PropertiesInitializer<T> {\n        void apply(T builder);\n    }\n\n    public static final class ConnAckBuilder {\n\n        private MqttConnectReturnCode returnCode;\n        private boolean sessionPresent;\n        private MqttProperties properties = MqttProperties.NO_PROPERTIES;\n        private ConnAckPropertiesBuilder propsBuilder;\n\n        private ConnAckBuilder() {\n        }\n\n        public ConnAckBuilder returnCode(MqttConnectReturnCode returnCode) {\n            this.returnCode = returnCode;\n            return this;\n        }\n\n        public ConnAckBuilder sessionPresent(boolean sessionPresent) {\n            this.sessionPresent = sessionPresent;\n            return this;\n        }\n\n        public ConnAckBuilder properties(MqttProperties properties) {\n            this.properties = properties;\n            return this;\n        }\n\n        public ConnAckBuilder properties(PropertiesInitializer<ConnAckPropertiesBuilder> consumer) {\n            if (propsBuilder == null) {\n                propsBuilder = new ConnAckPropertiesBuilder();\n            }\n            consumer.apply(propsBuilder);\n            return this;\n        }\n\n        public MqttConnAckMessage build() {\n            if (propsBuilder != null) {\n                properties = propsBuilder.build();\n            }\n            MqttFixedHeader mqttFixedHeader =\n                    new MqttFixedHeader(MqttMessageType.CONNACK, false, MqttQoS.AT_MOST_ONCE, false, 0);\n            MqttConnAckVariableHeader mqttConnAckVariableHeader =\n                    new MqttConnAckVariableHeader(returnCode, sessionPresent, properties);\n            return new MqttConnAckMessage(mqttFixedHeader, mqttConnAckVariableHeader);\n        }\n    }\n\n    public static final class ConnAckPropertiesBuilder {\n        private String clientId;\n        private Long sessionExpiryInterval;\n        private int receiveMaximum;\n        private Byte maximumQos;\n        private boolean retain;\n        private Long maximumPacketSize;\n        private int topicAliasMaximum;\n        private String reasonString;\n        private final MqttProperties.UserProperties userProperties = new MqttProperties.UserProperties();\n        private Boolean wildcardSubscriptionAvailable;\n        private Boolean subscriptionIdentifiersAvailable;\n        private Boolean sharedSubscriptionAvailable;\n        private Integer serverKeepAlive;\n        private String responseInformation;\n        private String serverReference;\n        private String authenticationMethod;\n        private byte[] authenticationData;\n\n        public MqttProperties build() {\n            final MqttProperties props = new MqttProperties();\n            if (clientId != null) {\n                props.add(new MqttProperties.StringProperty(MqttProperties.MqttPropertyType.ASSIGNED_CLIENT_IDENTIFIER.value(),\n                        clientId));\n            }\n            if (sessionExpiryInterval != null) {\n                props.add(new MqttProperties.IntegerProperty(\n                        MqttProperties.MqttPropertyType.SESSION_EXPIRY_INTERVAL.value(), sessionExpiryInterval.intValue()));\n            }\n            if (receiveMaximum > 0) {\n                props.add(new MqttProperties.IntegerProperty(MqttProperties.MqttPropertyType.RECEIVE_MAXIMUM.value(), receiveMaximum));\n            }\n            if (maximumQos != null) {\n                props.add(new MqttProperties.IntegerProperty(MqttProperties.MqttPropertyType.MAXIMUM_QOS.value(), receiveMaximum));\n            }\n            props.add(new MqttProperties.IntegerProperty(MqttProperties.MqttPropertyType.RETAIN_AVAILABLE.value(), retain ? 1 : 0));\n            if (maximumPacketSize != null) {\n                props.add(new MqttProperties.IntegerProperty(MqttProperties.MqttPropertyType.MAXIMUM_PACKET_SIZE.value(),\n                        maximumPacketSize.intValue()));\n            }\n            props.add(new MqttProperties.IntegerProperty(MqttProperties.MqttPropertyType.TOPIC_ALIAS_MAXIMUM.value(),\n                    topicAliasMaximum));\n            if (reasonString != null) {\n                props.add(new MqttProperties.StringProperty(MqttProperties.MqttPropertyType.REASON_STRING.value(), reasonString));\n            }\n            props.add(userProperties);\n            if (wildcardSubscriptionAvailable != null) {\n                props.add(new MqttProperties.IntegerProperty(MqttProperties.MqttPropertyType.WILDCARD_SUBSCRIPTION_AVAILABLE.value(),\n                        wildcardSubscriptionAvailable ? 1 : 0));\n            }\n            if (subscriptionIdentifiersAvailable != null) {\n                props.add(new MqttProperties.IntegerProperty(MqttProperties.MqttPropertyType.SUBSCRIPTION_IDENTIFIER_AVAILABLE.value(),\n                        subscriptionIdentifiersAvailable ? 1 : 0));\n            }\n            if (sharedSubscriptionAvailable != null) {\n                props.add(new MqttProperties.IntegerProperty(MqttProperties.MqttPropertyType.SHARED_SUBSCRIPTION_AVAILABLE.value(),\n                        sharedSubscriptionAvailable ? 1 : 0));\n            }\n            if (serverKeepAlive != null) {\n                props.add(new MqttProperties.IntegerProperty(MqttProperties.MqttPropertyType.SERVER_KEEP_ALIVE.value(),\n                        serverKeepAlive));\n            }\n            if (responseInformation != null) {\n                props.add(new MqttProperties.StringProperty(MqttProperties.MqttPropertyType.RESPONSE_INFORMATION.value(),\n                        responseInformation));\n            }\n            if (serverReference != null) {\n                props.add(new MqttProperties.StringProperty(MqttProperties.MqttPropertyType.SERVER_REFERENCE.value(),\n                        serverReference));\n            }\n            if (authenticationMethod != null) {\n                props.add(new MqttProperties.StringProperty(MqttProperties.MqttPropertyType.AUTHENTICATION_METHOD.value(),\n                        authenticationMethod));\n            }\n            if (authenticationData != null) {\n                props.add(new MqttProperties.BinaryProperty(MqttProperties.MqttPropertyType.AUTHENTICATION_DATA.value(),\n                        authenticationData));\n            }\n\n            return props;\n        }\n\n        public ConnAckPropertiesBuilder sessionExpiryInterval(long seconds) {\n            this.sessionExpiryInterval = seconds;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder receiveMaximum(int value) {\n            this.receiveMaximum = checkPositive(value, \"value\");\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder maximumQos(byte value) {\n            if (value != 0 && value != 1) {\n                throw new IllegalArgumentException(\"maximum QoS property could be 0 or 1\");\n            }\n            this.maximumQos = value;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder retainAvailable(boolean retain) {\n            this.retain = retain;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder maximumPacketSize(long size) {\n            this.maximumPacketSize = checkPositive(size, \"size\");\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder assignedClientId(String clientId) {\n            this.clientId = clientId;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder topicAliasMaximum(int value) {\n            this.topicAliasMaximum = value;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder reasonString(String reason) {\n            this.reasonString = reason;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder userProperty(String name, String value) {\n            userProperties.add(name, value);\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder wildcardSubscriptionAvailable(boolean value) {\n            this.wildcardSubscriptionAvailable = value;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder subscriptionIdentifiersAvailable(boolean value) {\n            this.subscriptionIdentifiersAvailable = value;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder sharedSubscriptionAvailable(boolean value) {\n            this.sharedSubscriptionAvailable = value;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder serverKeepAlive(int seconds) {\n            this.serverKeepAlive = seconds;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder responseInformation(String value) {\n            this.responseInformation = value;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder serverReference(String host) {\n            this.serverReference = host;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder authenticationMethod(String methodName) {\n            this.authenticationMethod = methodName;\n            return this;\n        }\n\n        public ConnAckPropertiesBuilder authenticationData(byte[] rawData) {\n            this.authenticationData = rawData.clone();\n            return this;\n        }\n    }\n\n    public static final class PubAckBuilder {\n\n        private int packetId;\n        private byte reasonCode;\n        private MqttProperties properties;\n\n        PubAckBuilder() {\n        }\n\n        public PubAckBuilder reasonCode(byte reasonCode) {\n            this.reasonCode = reasonCode;\n            return this;\n        }\n\n        public PubAckBuilder packetId(int packetId) {\n            this.packetId = packetId;\n            return this;\n        }\n\n        /**\n         * @deprecated use {@link PubAckBuilder#packetId(int)} instead\n         */\n        @Deprecated\n        public PubAckBuilder packetId(short packetId) {\n            return packetId(packetId & 0xFFFF);\n        }\n\n        public PubAckBuilder properties(MqttProperties properties) {\n            this.properties = properties;\n            return this;\n        }\n\n        public MqttMessage build() {\n            MqttFixedHeader mqttFixedHeader =\n                    new MqttFixedHeader(MqttMessageType.PUBACK, false, MqttQoS.AT_MOST_ONCE, false, 0);\n            MqttPubReplyMessageVariableHeader mqttPubAckVariableHeader =\n                    new MqttPubReplyMessageVariableHeader(packetId, reasonCode, properties);\n            return new MqttMessage(mqttFixedHeader, mqttPubAckVariableHeader);\n        }\n    }\n\n    public static final class SubAckBuilder {\n\n        private int packetId;\n        private MqttProperties properties;\n        private final List<MqttQoS> grantedQoses = new ArrayList<MqttQoS>();\n\n        SubAckBuilder() {\n        }\n\n        public SubAckBuilder packetId(int packetId) {\n            this.packetId = packetId;\n            return this;\n        }\n\n        /**\n         * @deprecated use {@link SubAckBuilder#packetId(int)} instead\n         */\n        @Deprecated\n        public SubAckBuilder packetId(short packetId) {\n            return packetId(packetId & 0xFFFF);\n        }\n\n        public SubAckBuilder properties(MqttProperties properties) {\n            this.properties = properties;\n            return this;\n        }\n\n        public SubAckBuilder addGrantedQos(MqttQoS qos) {\n            this.grantedQoses.add(qos);\n            return this;\n        }\n\n        public SubAckBuilder addGrantedQoses(MqttQoS... qoses) {\n            this.grantedQoses.addAll(Arrays.asList(qoses));\n            return this;\n        }\n\n        public MqttSubAckMessage build() {\n            MqttFixedHeader mqttFixedHeader =\n                    new MqttFixedHeader(MqttMessageType.SUBACK, false, MqttQoS.AT_MOST_ONCE, false, 0);\n            MqttMessageIdAndPropertiesVariableHeader mqttSubAckVariableHeader =\n                    new MqttMessageIdAndPropertiesVariableHeader(packetId, properties);\n\n            //transform to primitive types\n            int[] grantedQoses = new int[this.grantedQoses.size()];\n            int i = 0;\n            for (MqttQoS grantedQos : this.grantedQoses) {\n                grantedQoses[i++] = grantedQos.value();\n            }\n\n            MqttSubAckPayload subAckPayload = new MqttSubAckPayload(grantedQoses);\n            return new MqttSubAckMessage(mqttFixedHeader, mqttSubAckVariableHeader, subAckPayload);\n        }\n    }\n\n    public static final class UnsubAckBuilder {\n\n        private int packetId;\n        private MqttProperties properties;\n        private final List<Short> reasonCodes = new ArrayList<Short>();\n\n        UnsubAckBuilder() {\n        }\n\n        public UnsubAckBuilder packetId(int packetId) {\n            this.packetId = packetId;\n            return this;\n        }\n\n        /**\n         * @deprecated use {@link UnsubAckBuilder#packetId(int)} instead\n         */\n        @Deprecated\n        public UnsubAckBuilder packetId(short packetId) {\n            return packetId(packetId & 0xFFFF);\n        }\n\n        public UnsubAckBuilder properties(MqttProperties properties) {\n            this.properties = properties;\n            return this;\n        }\n\n        public UnsubAckBuilder addReasonCode(short reasonCode) {\n            this.reasonCodes.add(reasonCode);\n            return this;\n        }\n\n        public UnsubAckBuilder addReasonCodes(Short... reasonCodes) {\n            this.reasonCodes.addAll(Arrays.asList(reasonCodes));\n            return this;\n        }\n\n        public MqttUnsubAckMessage build() {\n            MqttFixedHeader mqttFixedHeader =\n                    new MqttFixedHeader(MqttMessageType.UNSUBACK, false, MqttQoS.AT_MOST_ONCE, false, 0);\n            MqttMessageIdAndPropertiesVariableHeader mqttSubAckVariableHeader =\n                    new MqttMessageIdAndPropertiesVariableHeader(packetId, properties);\n\n            MqttUnsubAckPayload subAckPayload = new MqttUnsubAckPayload(reasonCodes);\n            return new MqttUnsubAckMessage(mqttFixedHeader, mqttSubAckVariableHeader, subAckPayload);\n        }\n    }\n\n    public static final class DisconnectBuilder {\n\n        private MqttProperties properties;\n        private byte reasonCode;\n\n        DisconnectBuilder() {\n        }\n\n        public DisconnectBuilder properties(MqttProperties properties) {\n            this.properties = properties;\n            return this;\n        }\n\n        public DisconnectBuilder reasonCode(byte reasonCode) {\n            this.reasonCode = reasonCode;\n            return this;\n        }\n\n        public MqttMessage build() {\n            MqttFixedHeader mqttFixedHeader =\n                    new MqttFixedHeader(MqttMessageType.DISCONNECT, false, MqttQoS.AT_MOST_ONCE, false, 0);\n            MqttReasonCodeAndPropertiesVariableHeader mqttDisconnectVariableHeader =\n                    new MqttReasonCodeAndPropertiesVariableHeader(reasonCode, properties);\n\n            return new MqttMessage(mqttFixedHeader, mqttDisconnectVariableHeader);\n        }\n    }\n\n    public static final class AuthBuilder {\n\n        private MqttProperties properties;\n        private byte reasonCode;\n\n        AuthBuilder() {\n        }\n\n        public AuthBuilder properties(MqttProperties properties) {\n            this.properties = properties;\n            return this;\n        }\n\n        public AuthBuilder reasonCode(byte reasonCode) {\n            this.reasonCode = reasonCode;\n            return this;\n        }\n\n        public MqttMessage build() {\n            MqttFixedHeader mqttFixedHeader =\n                    new MqttFixedHeader(MqttMessageType.AUTH, false, MqttQoS.AT_MOST_ONCE, false, 0);\n            MqttReasonCodeAndPropertiesVariableHeader mqttAuthVariableHeader =\n                    new MqttReasonCodeAndPropertiesVariableHeader(reasonCode, properties);\n\n            return new MqttMessage(mqttFixedHeader, mqttAuthVariableHeader);\n        }\n    }\n\n    public static ConnectBuilder connect() {\n        return new ConnectBuilder();\n    }\n\n    public static ConnAckBuilder connAck() {\n        return new ConnAckBuilder();\n    }\n\n    public static PublishBuilder publish() {\n        return new PublishBuilder();\n    }\n\n    public static SubscribeBuilder subscribe() {\n        return new SubscribeBuilder();\n    }\n\n    public static UnsubscribeBuilder unsubscribe() {\n        return new UnsubscribeBuilder();\n    }\n\n    public static PubAckBuilder pubAck() {\n        return new PubAckBuilder();\n    }\n\n    public static SubAckBuilder subAck() {\n        return new SubAckBuilder();\n    }\n\n    public static UnsubAckBuilder unsubAck() {\n        return new UnsubAckBuilder();\n    }\n\n    public static DisconnectBuilder disconnect() {\n        return new DisconnectBuilder();\n    }\n\n    public static AuthBuilder auth() {\n        return new AuthBuilder();\n    }\n\n    private MqttMessageBuilders() {\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttMessageFactory.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.handler.codec.DecoderResult;\n\n/**\n * Utility class with factory methods to create different types of MQTT messages.\n */\npublic final class MqttMessageFactory {\n\n    public static MqttMessage newMessage(MqttFixedHeader mqttFixedHeader, Object variableHeader, Object payload) {\n        switch (mqttFixedHeader.messageType()) {\n            case CONNECT :\n                return new MqttConnectMessage(\n                        mqttFixedHeader,\n                        (MqttConnectVariableHeader) variableHeader,\n                        (MqttConnectPayload) payload);\n\n            case CONNACK:\n                return new MqttConnAckMessage(mqttFixedHeader, (MqttConnAckVariableHeader) variableHeader);\n\n            case SUBSCRIBE:\n                return new MqttSubscribeMessage(\n                        mqttFixedHeader,\n                        (MqttMessageIdVariableHeader) variableHeader,\n                        (MqttSubscribePayload) payload);\n\n            case SUBACK:\n                return new MqttSubAckMessage(\n                        mqttFixedHeader,\n                        (MqttMessageIdVariableHeader) variableHeader,\n                        (MqttSubAckPayload) payload);\n\n            case UNSUBACK:\n                return new MqttUnsubAckMessage(\n                        mqttFixedHeader,\n                        (MqttMessageIdVariableHeader) variableHeader,\n                        (MqttUnsubAckPayload) payload);\n\n            case UNSUBSCRIBE:\n                return new MqttUnsubscribeMessage(\n                        mqttFixedHeader,\n                        (MqttMessageIdVariableHeader) variableHeader,\n                        (MqttUnsubscribePayload) payload);\n\n            case PUBLISH:\n                return new MqttPublishMessage(\n                        mqttFixedHeader,\n                        (MqttPublishVariableHeader) variableHeader,\n                        (ByteBuf) payload);\n\n            case PUBACK:\n                //Having MqttPubReplyMessageVariableHeader or MqttMessageIdVariableHeader\n                return new MqttPubAckMessage(mqttFixedHeader, (MqttMessageIdVariableHeader) variableHeader);\n            case PUBREC:\n            case PUBREL:\n            case PUBCOMP:\n                //Having MqttPubReplyMessageVariableHeader or MqttMessageIdVariableHeader\n                return new MqttMessage(mqttFixedHeader, variableHeader);\n\n            case PINGREQ:\n            case PINGRESP:\n                return new MqttMessage(mqttFixedHeader);\n\n            case DISCONNECT:\n            case AUTH:\n                //Having MqttReasonCodeAndPropertiesVariableHeader\n                return new MqttMessage(mqttFixedHeader,\n                        variableHeader);\n\n            default:\n                throw new IllegalArgumentException(\"unknown message type: \" + mqttFixedHeader.messageType());\n        }\n    }\n\n    public static MqttMessage newInvalidMessage(Throwable cause) {\n        return new MqttMessage(null, null, null, DecoderResult.failure(cause));\n    }\n\n    public static MqttMessage newInvalidMessage(MqttFixedHeader mqttFixedHeader, Object variableHeader,\n                                                Throwable cause) {\n        return new MqttMessage(mqttFixedHeader, variableHeader, null, DecoderResult.failure(cause));\n    }\n\n    private MqttMessageFactory() { }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttMessageIdAndPropertiesVariableHeader.java",
    "content": "/*\n * Copyright 2020 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.StringUtil;\n\n/**\n * Variable Header containing, Packet Id and Properties as in MQTT v5 spec.\n */\npublic final class MqttMessageIdAndPropertiesVariableHeader extends MqttMessageIdVariableHeader {\n\n    private final MqttProperties properties;\n\n    public MqttMessageIdAndPropertiesVariableHeader(int messageId, MqttProperties properties) {\n        super(messageId);\n        if (messageId < 1 || messageId > 0xffff) {\n            throw new IllegalArgumentException(\"messageId: \" + messageId + \" (expected: 1 ~ 65535)\");\n        }\n        this.properties = MqttProperties.withEmptyDefaults(properties);\n    }\n\n    public MqttProperties properties() {\n        return properties;\n    }\n\n    @Override\n    public String toString() {\n        return StringUtil.simpleClassName(this) + \"[\" +\n                \"messageId=\" + messageId() +\n                \", properties=\" + properties +\n                ']';\n    }\n\n    @Override\n    MqttMessageIdAndPropertiesVariableHeader withDefaultEmptyProperties() {\n        return this;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttMessageIdVariableHeader.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.StringUtil;\n\n/**\n * Variable Header containing only Message Id\n * See <a href=\"https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#msg-id\">MQTTV3.1/msg-id</a>\n */\npublic class MqttMessageIdVariableHeader {\n\n    private final int messageId;\n\n    public static MqttMessageIdVariableHeader from(int messageId) {\n      if (messageId < 1 || messageId > 0xffff) {\n        throw new IllegalArgumentException(\"messageId: \" + messageId + \" (expected: 1 ~ 65535)\");\n      }\n      return new MqttMessageIdVariableHeader(messageId);\n    }\n\n    protected MqttMessageIdVariableHeader(int messageId) {\n        this.messageId = messageId;\n    }\n\n    public int messageId() {\n        return messageId;\n    }\n\n    @Override\n    public String toString() {\n        return new StringBuilder(StringUtil.simpleClassName(this))\n            .append('[')\n            .append(\"messageId=\").append(messageId)\n            .append(']')\n            .toString();\n    }\n\n    public MqttMessageIdAndPropertiesVariableHeader withEmptyProperties() {\n        return new MqttMessageIdAndPropertiesVariableHeader(messageId, MqttProperties.NO_PROPERTIES);\n    }\n\n    MqttMessageIdAndPropertiesVariableHeader withDefaultEmptyProperties() {\n        return withEmptyProperties();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttMessageType.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\n/**\n * MQTT Message Types.\n */\npublic enum MqttMessageType {\n    CONNECT(1),\n    CONNACK(2),\n    PUBLISH(3),\n    PUBACK(4),\n    PUBREC(5),\n    PUBREL(6),\n    PUBCOMP(7),\n    SUBSCRIBE(8),\n    SUBACK(9),\n    UNSUBSCRIBE(10),\n    UNSUBACK(11),\n    PINGREQ(12),\n    PINGRESP(13),\n    DISCONNECT(14),\n    AUTH(15);\n\n    private static final MqttMessageType[] VALUES;\n\n    static {\n        // this prevent values to be assigned with the wrong order\n        // and ensure valueOf to work fine\n        final MqttMessageType[] values = values();\n        VALUES = new MqttMessageType[values.length + 1];\n        for (MqttMessageType mqttMessageType : values) {\n            final int value = mqttMessageType.value;\n            if (VALUES[value] != null) {\n                throw new AssertionError(\"value already in use: \" + value);\n            }\n            VALUES[value] = mqttMessageType;\n        }\n    }\n\n    private final int value;\n\n    MqttMessageType(int value) {\n        this.value = value;\n    }\n\n    public int value() {\n        return value;\n    }\n\n    public static MqttMessageType valueOf(int type) {\n        if (type <= 0 || type >= VALUES.length) {\n            throw new IllegalArgumentException(\"unknown message type: \" + type);\n        }\n        return VALUES[type];\n    }\n}\n\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttProperties.java",
    "content": "/*\n * Copyright 2020 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.collection.IntObjectHashMap;\n\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.ArrayList;\n\n/**\n * MQTT Properties container\n * */\npublic final class MqttProperties {\n\n    public enum MqttPropertyType {\n        // single byte properties\n        PAYLOAD_FORMAT_INDICATOR(0x01),\n        REQUEST_PROBLEM_INFORMATION(0x17),\n        REQUEST_RESPONSE_INFORMATION(0x19),\n        MAXIMUM_QOS(0x24),\n        RETAIN_AVAILABLE(0x25),\n        WILDCARD_SUBSCRIPTION_AVAILABLE(0x28),\n        SUBSCRIPTION_IDENTIFIER_AVAILABLE(0x29),\n        SHARED_SUBSCRIPTION_AVAILABLE(0x2A),\n\n        // two bytes properties\n        SERVER_KEEP_ALIVE(0x13),\n        RECEIVE_MAXIMUM(0x21),\n        TOPIC_ALIAS_MAXIMUM(0x22),\n        TOPIC_ALIAS(0x23),\n\n        // four bytes properties\n        PUBLICATION_EXPIRY_INTERVAL(0x02),\n        SESSION_EXPIRY_INTERVAL(0x11),\n        WILL_DELAY_INTERVAL(0x18),\n        MAXIMUM_PACKET_SIZE(0x27),\n\n        // Variable Byte Integer\n        SUBSCRIPTION_IDENTIFIER(0x0B),\n\n        // UTF-8 Encoded String properties\n        CONTENT_TYPE(0x03),\n        RESPONSE_TOPIC(0x08),\n        ASSIGNED_CLIENT_IDENTIFIER(0x12),\n        AUTHENTICATION_METHOD(0x15),\n        RESPONSE_INFORMATION(0x1A),\n        SERVER_REFERENCE(0x1C),\n        REASON_STRING(0x1F),\n        USER_PROPERTY(0x26),\n\n        // Binary Data\n        CORRELATION_DATA(0x09),\n        AUTHENTICATION_DATA(0x16);\n\n        private static final MqttPropertyType[] VALUES;\n\n        static {\n            VALUES = new MqttPropertyType[43];\n            for (MqttPropertyType v : values()) {\n                VALUES[v.value] = v;\n            }\n        }\n\n        private final int value;\n\n        MqttPropertyType(int value) {\n            this.value = value;\n        }\n\n        public int value() {\n            return value;\n        }\n\n        public static MqttPropertyType valueOf(int type) {\n            MqttPropertyType t = null;\n            try {\n                t = VALUES[type];\n            } catch (ArrayIndexOutOfBoundsException ignored) {\n                // nop\n            }\n            if (t == null) {\n                throw new IllegalArgumentException(\"unknown property type: \" + type);\n            }\n            return t;\n        }\n    }\n\n    public static final MqttProperties NO_PROPERTIES = new MqttProperties(false);\n\n    static MqttProperties withEmptyDefaults(MqttProperties properties) {\n        if (properties == null) {\n            return MqttProperties.NO_PROPERTIES;\n        }\n        return properties;\n    }\n\n    /**\n     * MQTT property base class\n     *\n     * @param <T> property type\n     */\n    public abstract static class MqttProperty<T> {\n        final T value;\n        final int propertyId;\n\n        protected MqttProperty(int propertyId, T value) {\n            this.propertyId = propertyId;\n            this.value = value;\n        }\n\n        /**\n         * Get MQTT property value\n         *\n         * @return property value\n         */\n        public T value() {\n            return value;\n        }\n\n        /**\n         * Get MQTT property ID\n         * @return property ID\n         */\n        public int propertyId() {\n            return propertyId;\n        }\n\n        @Override\n        public int hashCode() {\n            return propertyId + 31 * value.hashCode();\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            if (obj == null || getClass() != obj.getClass()) {\n                return false;\n            }\n            MqttProperty that = (MqttProperty) obj;\n            return this.propertyId == that.propertyId && this.value.equals(that.value);\n        }\n    }\n\n    public static final class IntegerProperty extends MqttProperty<Integer> {\n\n        public IntegerProperty(int propertyId, Integer value) {\n            super(propertyId, value);\n        }\n\n        @Override\n        public String toString() {\n            return \"IntegerProperty(\" + propertyId + \", \" + value + \")\";\n        }\n    }\n\n    public static final class StringProperty extends MqttProperty<String> {\n\n        public StringProperty(int propertyId, String value) {\n            super(propertyId, value);\n        }\n\n        @Override\n        public String toString() {\n            return \"StringProperty(\" + propertyId + \", \" + value + \")\";\n        }\n    }\n\n    public static final class StringPair {\n        public final String key;\n        public final String value;\n\n        public StringPair(String key, String value) {\n            this.key = key;\n            this.value = value;\n        }\n\n        @Override\n        public int hashCode() {\n            return key.hashCode() + 31 * value.hashCode();\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            if (obj == null || getClass() != obj.getClass()) {\n                return false;\n            }\n            StringPair that = (StringPair) obj;\n\n            return that.key.equals(this.key) && that.value.equals(this.value);\n        }\n    }\n\n    //User properties are the only properties that may be included multiple times and\n    //are the only properties where ordering is required. Therefore, they need a special handling\n    public static final class UserProperties extends MqttProperty<List<StringPair>> {\n        public UserProperties() {\n            super(MqttPropertyType.USER_PROPERTY.value, new ArrayList<StringPair>());\n        }\n\n        /**\n         * Create user properties from the collection of the String pair values\n         *\n         * @param values string pairs. Collection entries are copied, collection itself isn't shared\n         */\n        public UserProperties(Collection<StringPair> values) {\n            this();\n            this.value.addAll(values);\n        }\n\n        private static UserProperties fromUserPropertyCollection(Collection<UserProperty> properties) {\n            UserProperties userProperties = new UserProperties();\n            for (UserProperty property: properties) {\n                userProperties.add(new StringPair(property.value.key, property.value.value));\n            }\n            return userProperties;\n        }\n\n        public void add(StringPair pair) {\n            this.value.add(pair);\n        }\n\n        public void add(String key, String value) {\n            this.value.add(new StringPair(key, value));\n        }\n\n        @Override\n        public String toString() {\n            StringBuilder builder = new StringBuilder(\"UserProperties(\");\n            boolean first = true;\n            for (StringPair pair: value) {\n                if (!first) {\n                    builder.append(\", \");\n                }\n                builder.append(pair.key + \"->\" + pair.value);\n                first = false;\n            }\n            builder.append(\")\");\n            return builder.toString();\n        }\n    }\n\n    public static final class UserProperty extends MqttProperty<StringPair> {\n        public UserProperty(String key, String value) {\n            super(MqttPropertyType.USER_PROPERTY.value, new StringPair(key, value));\n        }\n\n        @Override\n        public String toString() {\n            return \"UserProperty(\" + value.key + \", \" + value.value + \")\";\n        }\n    }\n\n    public static final class BinaryProperty extends MqttProperty<byte[]> {\n\n        public BinaryProperty(int propertyId, byte[] value) {\n            super(propertyId, value);\n        }\n\n        @Override\n        public String toString() {\n            return \"BinaryProperty(\" + propertyId + \", \" + value.length + \" bytes)\";\n        }\n    }\n\n    public MqttProperties() {\n        this(true);\n    }\n\n    private MqttProperties(boolean canModify) {\n        this.canModify = canModify;\n    }\n\n    private IntObjectHashMap<MqttProperty> props;\n    private List<UserProperty> userProperties;\n    private List<IntegerProperty> subscriptionIds;\n    private final boolean canModify;\n\n    public void add(MqttProperty property) {\n        if (!canModify) {\n            throw new UnsupportedOperationException(\"adding property isn't allowed\");\n        }\n        IntObjectHashMap<MqttProperty> props = this.props;\n        if (property.propertyId == MqttPropertyType.USER_PROPERTY.value) {\n            List<UserProperty> userProperties = this.userProperties;\n            if (userProperties == null) {\n                userProperties = new ArrayList<UserProperty>(1);\n                this.userProperties = userProperties;\n            }\n            if (property instanceof UserProperty) {\n                userProperties.add((UserProperty) property);\n            } else if (property instanceof UserProperties) {\n                for (StringPair pair: ((UserProperties) property).value) {\n                    userProperties.add(new UserProperty(pair.key, pair.value));\n                }\n            } else {\n                throw new IllegalArgumentException(\"User property must be of UserProperty or UserProperties type\");\n            }\n        } else if (property.propertyId == MqttPropertyType.SUBSCRIPTION_IDENTIFIER.value) {\n            List<IntegerProperty> subscriptionIds = this.subscriptionIds;\n            if (subscriptionIds == null) {\n                subscriptionIds = new ArrayList<IntegerProperty>(1);\n                this.subscriptionIds = subscriptionIds;\n            }\n            if (property instanceof IntegerProperty) {\n                subscriptionIds.add((IntegerProperty) property);\n            } else {\n                throw new IllegalArgumentException(\"Subscription ID must be an integer property\");\n            }\n        } else {\n            if (props == null) {\n                props = new IntObjectHashMap<MqttProperty>();\n                this.props = props;\n            }\n            props.put(property.propertyId, property);\n        }\n    }\n\n    public Collection<? extends MqttProperty> listAll() {\n        IntObjectHashMap<MqttProperty> props = this.props;\n        if (props == null && subscriptionIds == null && userProperties == null) {\n            return Collections.<MqttProperty>emptyList();\n        }\n        if (subscriptionIds == null && userProperties == null) {\n            return props.values();\n        }\n        if (props == null && userProperties == null) {\n            return subscriptionIds;\n        }\n        List<MqttProperty> propValues = new ArrayList<MqttProperty>(props != null ? props.size() : 1);\n        if (props != null) {\n            propValues.addAll(props.values());\n        }\n        if (subscriptionIds != null) {\n            propValues.addAll(subscriptionIds);\n        }\n        if (userProperties != null) {\n            propValues.add(UserProperties.fromUserPropertyCollection(userProperties));\n        }\n        return propValues;\n    }\n\n    public boolean isEmpty() {\n        IntObjectHashMap<MqttProperty> props = this.props;\n        return props == null || props.isEmpty();\n    }\n\n    /**\n     * Get property by ID. If there are multiple properties of this type (can be with Subscription ID)\n     * then return the first one.\n     *\n     * @param propertyId ID of the property\n     * @return a property if it is set, null otherwise\n     */\n    public MqttProperty getProperty(int propertyId) {\n        if (propertyId == MqttPropertyType.USER_PROPERTY.value) {\n            //special handling to keep compatibility with earlier versions\n            List<UserProperty> userProperties = this.userProperties;\n            if (userProperties == null) {\n                return null;\n            }\n            return UserProperties.fromUserPropertyCollection(userProperties);\n        }\n        if (propertyId == MqttPropertyType.SUBSCRIPTION_IDENTIFIER.value) {\n            List<IntegerProperty> subscriptionIds = this.subscriptionIds;\n            if (subscriptionIds == null || subscriptionIds.isEmpty()) {\n                return null;\n            }\n            return subscriptionIds.get(0);\n        }\n        IntObjectHashMap<MqttProperty> props = this.props;\n        return props == null ? null : props.get(propertyId);\n    }\n\n    /**\n     * Get properties by ID.\n     * Some properties (Subscription ID and User Properties) may occur multiple times,\n     * this method returns all their values in order.\n     *\n     * @param propertyId ID of the property\n     * @return all properties having specified ID\n     */\n    public List<? extends MqttProperty> getProperties(int propertyId) {\n        if (propertyId == MqttPropertyType.USER_PROPERTY.value) {\n            return userProperties == null ? Collections.<MqttProperty>emptyList() : userProperties;\n        }\n        if (propertyId == MqttPropertyType.SUBSCRIPTION_IDENTIFIER.value) {\n            return subscriptionIds == null ? Collections.<MqttProperty>emptyList() : subscriptionIds;\n        }\n        IntObjectHashMap<MqttProperty> props = this.props;\n        return (props == null || !props.containsKey(propertyId)) ?\n                Collections.<MqttProperty>emptyList() :\n                Collections.singletonList(props.get(propertyId));\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttPubAckMessage.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\n/**\n * See <a href=\"https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#puback\">MQTTV3.1/puback</a>\n */\npublic final class MqttPubAckMessage extends MqttMessage {\n\n    public MqttPubAckMessage(MqttFixedHeader mqttFixedHeader, MqttMessageIdVariableHeader variableHeader) {\n        super(mqttFixedHeader, variableHeader);\n    }\n\n    @Override\n    public MqttMessageIdVariableHeader variableHeader() {\n        return (MqttMessageIdVariableHeader) super.variableHeader();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttPubReplyMessageVariableHeader.java",
    "content": "/*\n * Copyright 2020 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.StringUtil;\n\n/**\n * Variable Header containing Packet Id, reason code and Properties as in MQTT v5 spec.\n */\npublic final class MqttPubReplyMessageVariableHeader extends MqttMessageIdVariableHeader {\n\n    private final byte reasonCode;\n    private final MqttProperties properties;\n\n    public static final byte REASON_CODE_OK = 0;\n\n    public MqttPubReplyMessageVariableHeader(int messageId, byte reasonCode, MqttProperties properties) {\n        super(messageId);\n        if (messageId < 1 || messageId > 0xffff) {\n            throw new IllegalArgumentException(\"messageId: \" + messageId + \" (expected: 1 ~ 65535)\");\n        }\n        this.reasonCode = reasonCode;\n        this.properties = MqttProperties.withEmptyDefaults(properties);\n    }\n\n    public byte reasonCode() {\n        return reasonCode;\n    }\n\n    public MqttProperties properties() {\n        return properties;\n    }\n\n    @Override\n    public String toString() {\n        return StringUtil.simpleClassName(this) + \"[\" +\n                \"messageId=\" + messageId() +\n                \", reasonCode=\" + reasonCode +\n                \", properties=\" + properties +\n                ']';\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttPublishMessage.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.ByteBufHolder;\nimport io.netty.buffer.ByteBufUtil;\n\n/**\n * See <a href=\"https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#publish\">MQTTV3.1/publish</a>\n */\npublic class MqttPublishMessage extends MqttMessage implements ByteBufHolder {\n\n    public MqttPublishMessage(\n            MqttFixedHeader mqttFixedHeader,\n            MqttPublishVariableHeader variableHeader,\n            ByteBuf payload) {\n        super(mqttFixedHeader, variableHeader, payload);\n    }\n\n    @Override\n    public MqttPublishVariableHeader variableHeader() {\n        return (MqttPublishVariableHeader) super.variableHeader();\n    }\n\n    @Override\n    public ByteBuf payload() {\n        return content();\n    }\n\n    @Override\n    public ByteBuf content() {\n        return ByteBufUtil.ensureAccessible((ByteBuf) super.payload());\n    }\n\n    @Override\n    public MqttPublishMessage copy() {\n        return replace(content().copy());\n    }\n\n    @Override\n    public MqttPublishMessage duplicate() {\n        return replace(content().duplicate());\n    }\n\n    @Override\n    public MqttPublishMessage retainedDuplicate() {\n        return replace(content().retainedDuplicate());\n    }\n\n    @Override\n    public MqttPublishMessage replace(ByteBuf content) {\n        return new MqttPublishMessage(fixedHeader(), variableHeader(), content);\n    }\n\n    @Override\n    public int refCnt() {\n        return content().refCnt();\n    }\n\n    @Override\n    public MqttPublishMessage retain() {\n        content().retain();\n        return this;\n    }\n\n    @Override\n    public MqttPublishMessage retain(int increment) {\n        content().retain(increment);\n        return this;\n    }\n\n    @Override\n    public MqttPublishMessage touch() {\n        content().touch();\n        return this;\n    }\n\n    @Override\n    public MqttPublishMessage touch(Object hint) {\n        content().touch(hint);\n        return this;\n    }\n\n    @Override\n    public boolean release() {\n        return content().release();\n    }\n\n    @Override\n    public boolean release(int decrement) {\n        return content().release(decrement);\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttPublishVariableHeader.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.StringUtil;\n\n/**\n * Variable Header of the {@link MqttPublishMessage}\n */\npublic final class MqttPublishVariableHeader {\n\n    private final String topicName;\n    private int packetId;\n    private final MqttProperties properties;\n\n    public MqttPublishVariableHeader(String topicName, int packetId) {\n        this(topicName, packetId, MqttProperties.NO_PROPERTIES);\n    }\n\n    public MqttPublishVariableHeader(String topicName, int packetId, MqttProperties properties) {\n        this.topicName = topicName;\n        this.packetId = packetId;\n        this.properties = MqttProperties.withEmptyDefaults(properties);\n    }\n\n    public String topicName() {\n        return topicName;\n    }\n\n    /**\n     * @deprecated Use {@link #packetId()} instead.\n     */\n    @Deprecated\n    public int messageId() {\n        return packetId;\n    }\n\n    public int packetId() {\n        return packetId;\n    }\n\n    public MqttProperties properties() {\n        return properties;\n    }\n\n    public void setPacketId(int packetId) {\n        this.packetId = packetId;\n    }\n\n    @Override\n    public String toString() {\n        return new StringBuilder(StringUtil.simpleClassName(this))\n            .append('[')\n            .append(\"topicName=\").append(topicName)\n            .append(\", packetId=\").append(packetId)\n            .append(']')\n            .toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttQoS.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License, version 2.0 (the\n * \"License\"); you may not use this file except in compliance with the License. You may obtain a\n * copy of the License at:\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under the License\n * is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express\n * or implied. See the License for the specific language governing permissions and limitations under\n * the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\npublic enum MqttQoS {\n    AT_MOST_ONCE(0),\n    AT_LEAST_ONCE(1),\n    EXACTLY_ONCE(2),\n    FAILURE(0x80);\n\n    private final int value;\n\n    MqttQoS(int value) {\n        this.value = value;\n    }\n\n    public int value() {\n        return value;\n    }\n\n    public static MqttQoS valueOf(int value) {\n        switch (value) {\n        case 0:\n            return AT_MOST_ONCE;\n        case 1:\n            return AT_LEAST_ONCE;\n        case 2:\n            return EXACTLY_ONCE;\n        case 0x80:\n            return FAILURE;\n        default:\n            throw new IllegalArgumentException(\"invalid QoS: \" + value);\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttReasonCodeAndPropertiesVariableHeader.java",
    "content": "/*\n * Copyright 2020 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.StringUtil;\n\n/**\n * Variable Header for AUTH and DISCONNECT messages represented by {@link MqttMessage}\n */\npublic final class MqttReasonCodeAndPropertiesVariableHeader {\n\n    private final byte reasonCode;\n    private final MqttProperties properties;\n\n    public static final byte REASON_CODE_OK = 0;\n\n    public MqttReasonCodeAndPropertiesVariableHeader(byte reasonCode,\n                                                     MqttProperties properties) {\n        this.reasonCode = reasonCode;\n        this.properties = MqttProperties.withEmptyDefaults(properties);\n    }\n\n    public byte reasonCode() {\n        return reasonCode;\n    }\n\n    public MqttProperties properties() {\n        return properties;\n    }\n\n    @Override\n    public String toString() {\n        return new StringBuilder(StringUtil.simpleClassName(this))\n            .append('[')\n            .append(\"reasonCode=\").append(reasonCode)\n            .append(\", properties=\").append(properties)\n            .append(']')\n            .toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttSubAckMessage.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\n/**\n * See <a href=\"https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#suback\">MQTTV3.1/suback</a>\n */\npublic final class MqttSubAckMessage extends MqttMessage {\n\n    public MqttSubAckMessage(\n            MqttFixedHeader mqttFixedHeader,\n            MqttMessageIdAndPropertiesVariableHeader variableHeader,\n            MqttSubAckPayload payload) {\n        super(mqttFixedHeader, variableHeader, payload);\n    }\n\n    public MqttSubAckMessage(\n            MqttFixedHeader mqttFixedHeader,\n            MqttMessageIdVariableHeader variableHeader,\n            MqttSubAckPayload payload) {\n        this(mqttFixedHeader, variableHeader.withDefaultEmptyProperties(), payload);\n    }\n\n    @Override\n    public MqttMessageIdVariableHeader variableHeader() {\n        return (MqttMessageIdVariableHeader) super.variableHeader();\n    }\n\n    public MqttMessageIdAndPropertiesVariableHeader idAndPropertiesVariableHeader() {\n        return (MqttMessageIdAndPropertiesVariableHeader) super.variableHeader();\n    }\n\n    @Override\n    public MqttSubAckPayload payload() {\n        return (MqttSubAckPayload) super.payload();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttSubAckPayload.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.ObjectUtil;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Payload of the {@link MqttSubAckMessage}\n */\npublic class MqttSubAckPayload {\n\n    private final List<Integer> reasonCodes;\n\n    public MqttSubAckPayload(int... reasonCodes) {\n        ObjectUtil.checkNotNull(reasonCodes, \"reasonCodes\");\n\n        List<Integer> list = new ArrayList<Integer>(reasonCodes.length);\n        for (int v: reasonCodes) {\n            list.add(v);\n        }\n        this.reasonCodes = Collections.unmodifiableList(list);\n    }\n\n    public MqttSubAckPayload(Iterable<Integer> reasonCodes) {\n        ObjectUtil.checkNotNull(reasonCodes, \"reasonCodes\");\n        List<Integer> list = new ArrayList<Integer>();\n        for (Integer v: reasonCodes) {\n            if (v == null) {\n                break;\n            }\n            list.add(v);\n        }\n        this.reasonCodes = Collections.unmodifiableList(list);\n    }\n\n    public List<Integer> grantedQoSLevels() {\n        List<Integer> qosLevels = new ArrayList<Integer>(reasonCodes.size());\n        for (int code: reasonCodes) {\n            if (code > MqttQoS.EXACTLY_ONCE.value()) {\n                qosLevels.add(MqttQoS.FAILURE.value());\n            } else {\n                qosLevels.add(code);\n            }\n        }\n        return qosLevels;\n    }\n\n    public List<Integer> reasonCodes() {\n        return reasonCodes;\n    }\n\n    @Override\n    public String toString() {\n        return new StringBuilder(StringUtil.simpleClassName(this))\n            .append('[')\n            .append(\"reasonCodes=\").append(reasonCodes)\n            .append(']')\n            .toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttSubscribeMessage.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\n/**\n * See <a href=\"https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#subscribe\">\n *     MQTTV3.1/subscribe</a>\n */\npublic final class MqttSubscribeMessage extends MqttMessage {\n\n    public MqttSubscribeMessage(\n            MqttFixedHeader mqttFixedHeader,\n            MqttMessageIdAndPropertiesVariableHeader variableHeader,\n            MqttSubscribePayload payload) {\n        super(mqttFixedHeader, variableHeader, payload);\n    }\n\n    public MqttSubscribeMessage(\n            MqttFixedHeader mqttFixedHeader,\n            MqttMessageIdVariableHeader variableHeader,\n            MqttSubscribePayload payload) {\n        this(mqttFixedHeader, variableHeader.withDefaultEmptyProperties(), payload);\n    }\n\n    @Override\n    public MqttMessageIdVariableHeader variableHeader() {\n        return (MqttMessageIdVariableHeader) super.variableHeader();\n    }\n\n    public MqttMessageIdAndPropertiesVariableHeader idAndPropertiesVariableHeader() {\n        return (MqttMessageIdAndPropertiesVariableHeader) super.variableHeader();\n    }\n\n    @Override\n    public MqttSubscribePayload payload() {\n        return (MqttSubscribePayload) super.payload();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttSubscribePayload.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Payload of the {@link MqttSubscribeMessage}\n */\npublic final class MqttSubscribePayload {\n\n    private final List<MqttTopicSubscription> topicSubscriptions;\n\n    public MqttSubscribePayload(List<MqttTopicSubscription> topicSubscriptions) {\n        this.topicSubscriptions = Collections.unmodifiableList(topicSubscriptions);\n    }\n\n    public List<MqttTopicSubscription> topicSubscriptions() {\n        return topicSubscriptions;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder(StringUtil.simpleClassName(this)).append('[');\n        for (int i = 0; i < topicSubscriptions.size(); i++) {\n            builder.append(topicSubscriptions.get(i)).append(\", \");\n        }\n        if (!topicSubscriptions.isEmpty()) {\n            builder.setLength(builder.length() - 2);\n        }\n        return builder.append(']').toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttSubscriptionOption.java",
    "content": "/*\n * Copyright 2020 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage io.netty.handler.codec.mqtt;\n\n/**\n * Model the SubscriptionOption used in Subscribe MQTT v5 packet\n */\npublic final class MqttSubscriptionOption {\n\n    public enum RetainedHandlingPolicy {\n        SEND_AT_SUBSCRIBE(0),\n        SEND_AT_SUBSCRIBE_IF_NOT_YET_EXISTS(1),\n        DONT_SEND_AT_SUBSCRIBE(2);\n\n        private final int value;\n\n        RetainedHandlingPolicy(int value) {\n            this.value = value;\n        }\n\n        public int value() {\n            return value;\n        }\n\n        public static RetainedHandlingPolicy valueOf(int value) {\n            switch (value) {\n            case 0:\n                return SEND_AT_SUBSCRIBE;\n            case 1:\n                return SEND_AT_SUBSCRIBE_IF_NOT_YET_EXISTS;\n            case 2:\n                return DONT_SEND_AT_SUBSCRIBE;\n            default:\n                throw new IllegalArgumentException(\"invalid RetainedHandlingPolicy: \" + value);\n            }\n        }\n    }\n\n    private final MqttQoS qos;\n    private final boolean noLocal;\n    private final boolean retainAsPublished;\n    private final RetainedHandlingPolicy retainHandling;\n\n    public static MqttSubscriptionOption onlyFromQos(MqttQoS qos) {\n        return new MqttSubscriptionOption(qos, false, false, RetainedHandlingPolicy.SEND_AT_SUBSCRIBE);\n    }\n\n    public MqttSubscriptionOption(MqttQoS qos,\n                                  boolean noLocal,\n                                  boolean retainAsPublished,\n                                  RetainedHandlingPolicy retainHandling) {\n        this.qos = qos;\n        this.noLocal = noLocal;\n        this.retainAsPublished = retainAsPublished;\n        this.retainHandling = retainHandling;\n    }\n\n    public MqttQoS qos() {\n        return qos;\n    }\n\n    public boolean isNoLocal() {\n        return noLocal;\n    }\n\n    public boolean isRetainAsPublished() {\n        return retainAsPublished;\n    }\n\n    public RetainedHandlingPolicy retainHandling() {\n        return retainHandling;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (o == null || getClass() != o.getClass()) {\n            return false;\n        }\n\n        MqttSubscriptionOption that = (MqttSubscriptionOption) o;\n\n        if (noLocal != that.noLocal) {\n            return false;\n        }\n        if (retainAsPublished != that.retainAsPublished) {\n            return false;\n        }\n        if (qos != that.qos) {\n            return false;\n        }\n        return retainHandling == that.retainHandling;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = qos.hashCode();\n        result = 31 * result + (noLocal ? 1 : 0);\n        result = 31 * result + (retainAsPublished ? 1 : 0);\n        result = 31 * result + retainHandling.hashCode();\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return \"SubscriptionOption[\" +\n                \"qos=\" + qos +\n                \", noLocal=\" + noLocal +\n                \", retainAsPublished=\" + retainAsPublished +\n                \", retainHandling=\" + retainHandling +\n                ']';\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttTopicSubscription.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.StringUtil;\n\n/**\n * Contains a topic name and Qos Level.\n * This is part of the {@link MqttSubscribePayload}\n */\npublic final class MqttTopicSubscription {\n\n    private final String topicFilter;\n    private final MqttSubscriptionOption option;\n\n    public MqttTopicSubscription(String topicFilter, MqttQoS qualityOfService) {\n        this.topicFilter = topicFilter;\n        this.option = MqttSubscriptionOption.onlyFromQos(qualityOfService);\n    }\n\n    public MqttTopicSubscription(String topicFilter, MqttSubscriptionOption option) {\n        this.topicFilter = topicFilter;\n        this.option = option;\n    }\n\n    public String topicName() {\n        return topicFilter;\n    }\n\n    public MqttQoS qualityOfService() {\n        return option.qos();\n    }\n\n    public MqttSubscriptionOption option() {\n        return option;\n    }\n\n    @Override\n    public String toString() {\n        return new StringBuilder(StringUtil.simpleClassName(this))\n            .append('[')\n            .append(\"topicFilter=\").append(topicFilter)\n            .append(\", option=\").append(this.option)\n            .append(']')\n            .toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttUnacceptableProtocolVersionException.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.handler.codec.DecoderException;\n\n/**\n * A {@link MqttUnacceptableProtocolVersionException} which is thrown when\n * a CONNECT request contains unacceptable protocol version.\n */\npublic final class MqttUnacceptableProtocolVersionException extends DecoderException {\n\n    private static final long serialVersionUID = 4914652213232455749L;\n\n    /**\n     * Creates a new instance\n     */\n    public MqttUnacceptableProtocolVersionException() { }\n\n    /**\n     * Creates a new instance\n     */\n    public MqttUnacceptableProtocolVersionException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    /**\n     * Creates a new instance\n     */\n    public MqttUnacceptableProtocolVersionException(String message) {\n        super(message);\n    }\n\n    /**\n     * Creates a new instance\n     */\n    public MqttUnacceptableProtocolVersionException(Throwable cause) {\n        super(cause);\n    }\n\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttUnsubAckMessage.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\n/**\n * See <a href=\"https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#unsuback\">\n *     MQTTV3.1/unsuback</a>\n */\npublic final class MqttUnsubAckMessage extends MqttMessage {\n\n    public MqttUnsubAckMessage(MqttFixedHeader mqttFixedHeader,\n                               MqttMessageIdAndPropertiesVariableHeader variableHeader,\n                               MqttUnsubAckPayload payload) {\n        super(mqttFixedHeader, variableHeader, MqttUnsubAckPayload.withEmptyDefaults(payload));\n    }\n\n    public MqttUnsubAckMessage(MqttFixedHeader mqttFixedHeader,\n                               MqttMessageIdVariableHeader variableHeader,\n                               MqttUnsubAckPayload payload) {\n        this(mqttFixedHeader, fallbackVariableHeader(variableHeader), payload);\n    }\n    public MqttUnsubAckMessage(MqttFixedHeader mqttFixedHeader,\n                               MqttMessageIdVariableHeader variableHeader) {\n        this(mqttFixedHeader, variableHeader, null);\n    }\n\n    private static MqttMessageIdAndPropertiesVariableHeader fallbackVariableHeader(\n            MqttMessageIdVariableHeader variableHeader) {\n        if (variableHeader instanceof MqttMessageIdAndPropertiesVariableHeader) {\n            return (MqttMessageIdAndPropertiesVariableHeader) variableHeader;\n        }\n        return new MqttMessageIdAndPropertiesVariableHeader(variableHeader.messageId(), MqttProperties.NO_PROPERTIES);\n    }\n\n    @Override\n    public MqttMessageIdVariableHeader variableHeader() {\n        return (MqttMessageIdVariableHeader) super.variableHeader();\n    }\n\n    public MqttMessageIdAndPropertiesVariableHeader idAndPropertiesVariableHeader() {\n        return (MqttMessageIdAndPropertiesVariableHeader) super.variableHeader();\n    }\n\n    @Override\n    public MqttUnsubAckPayload payload() {\n        return (MqttUnsubAckPayload) super.payload();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttUnsubAckPayload.java",
    "content": "/*\n * Copyright 2020 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.ObjectUtil;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Payload for MQTT unsuback message as in V5.\n */\npublic final class MqttUnsubAckPayload {\n\n    private final List<Short> unsubscribeReasonCodes;\n\n    private static final MqttUnsubAckPayload EMPTY = new MqttUnsubAckPayload();\n\n    public static MqttUnsubAckPayload withEmptyDefaults(MqttUnsubAckPayload payload) {\n        if (payload == null) {\n            return EMPTY;\n        } else {\n            return payload;\n        }\n    }\n\n    public MqttUnsubAckPayload(short... unsubscribeReasonCodes) {\n        ObjectUtil.checkNotNull(unsubscribeReasonCodes, \"unsubscribeReasonCodes\");\n\n        List<Short> list = new ArrayList<Short>(unsubscribeReasonCodes.length);\n        for (Short v: unsubscribeReasonCodes) {\n            list.add(v);\n        }\n        this.unsubscribeReasonCodes = Collections.unmodifiableList(list);\n    }\n\n    public MqttUnsubAckPayload(Iterable<Short> unsubscribeReasonCodes) {\n        ObjectUtil.checkNotNull(unsubscribeReasonCodes, \"unsubscribeReasonCodes\");\n\n        List<Short> list = new ArrayList<Short>();\n        for (Short v: unsubscribeReasonCodes) {\n            ObjectUtil.checkNotNull(v, \"unsubscribeReasonCode\");\n            list.add(v);\n        }\n        this.unsubscribeReasonCodes = Collections.unmodifiableList(list);\n    }\n\n    public List<Short> unsubscribeReasonCodes() {\n        return unsubscribeReasonCodes;\n    }\n\n    @Override\n    public String toString() {\n        return new StringBuilder(StringUtil.simpleClassName(this))\n                .append('[')\n                .append(\"unsubscribeReasonCodes=\").append(unsubscribeReasonCodes)\n                .append(']')\n                .toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttUnsubscribeMessage.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\n/**\n * See <a href=\"https://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#unsubscribe\">\n *     MQTTV3.1/unsubscribe</a>\n */\npublic final class MqttUnsubscribeMessage extends MqttMessage {\n\n    public MqttUnsubscribeMessage(\n            MqttFixedHeader mqttFixedHeader,\n            MqttMessageIdAndPropertiesVariableHeader variableHeader,\n            MqttUnsubscribePayload payload) {\n        super(mqttFixedHeader, variableHeader, payload);\n    }\n\n    public MqttUnsubscribeMessage(\n            MqttFixedHeader mqttFixedHeader,\n            MqttMessageIdVariableHeader variableHeader,\n            MqttUnsubscribePayload payload) {\n        this(mqttFixedHeader, variableHeader.withDefaultEmptyProperties(), payload);\n    }\n\n    @Override\n    public MqttMessageIdVariableHeader variableHeader() {\n        return (MqttMessageIdVariableHeader) super.variableHeader();\n    }\n\n    public MqttMessageIdAndPropertiesVariableHeader idAndPropertiesVariableHeader() {\n        return (MqttMessageIdAndPropertiesVariableHeader) super.variableHeader();\n    }\n\n    @Override\n    public MqttUnsubscribePayload payload() {\n        return (MqttUnsubscribePayload) super.payload();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttUnsubscribePayload.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Payload of the {@link MqttUnsubscribeMessage}\n */\npublic final class MqttUnsubscribePayload {\n\n    private final List<String> topics;\n\n    public MqttUnsubscribePayload(List<String> topics) {\n        this.topics = Collections.unmodifiableList(topics);\n    }\n\n    public List<String> topics() {\n        return topics;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder(StringUtil.simpleClassName(this)).append('[');\n        for (int i = 0; i < topics.size(); i++) {\n            builder.append(\"topicName = \").append(topics.get(i)).append(\", \");\n        }\n        if (!topics.isEmpty()) {\n            builder.setLength(builder.length() - 2);\n        }\n        return builder.append(\"]\").toString();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/MqttVersion.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License,\n * version 2.0 (the \"License\"); you may not use this file except in compliance\n * with the License. You may obtain a copy of the License at:\n *\n *   https://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, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\npackage io.netty.handler.codec.mqtt;\n\nimport io.netty.util.CharsetUtil;\nimport io.netty.util.internal.ObjectUtil;\n\n/**\n * Mqtt version specific constant values used by multiple classes in mqtt-codec.\n */\npublic enum MqttVersion {\n    MQTT_3_1(\"MQIsdp\", (byte) 3),\n    MQTT_3_1_1(\"MQTT\", (byte) 4),\n    MQTT_5(\"MQTT\", (byte) 5),\n    Wildfire_2(\"MQTT\", (byte) 6),\n    Wildfire_Future(\"MQTT\", (byte) 7);\n\n    private final String name;\n    private final byte level;\n\n    MqttVersion(String protocolName, byte protocolLevel) {\n        name = ObjectUtil.checkNotNull(protocolName, \"protocolName\");\n        level = protocolLevel;\n    }\n\n    public String protocolName() {\n        return name;\n    }\n\n    public byte[] protocolNameBytes() {\n        return name.getBytes(CharsetUtil.UTF_8);\n    }\n\n    public byte protocolLevel() {\n        return level;\n    }\n\n    public static MqttVersion fromProtocolNameAndLevel(String protocolName, byte protocolLevel) {\n        MqttVersion mv = null;\n        switch (protocolLevel) {\n        case 3:\n            mv = MQTT_3_1;\n            break;\n        case 4:\n            mv = MQTT_3_1_1;\n            break;\n        case 5:\n            mv = MQTT_5;\n            break;\n        case 6:\n            mv = Wildfire_2;\n            break;\n        case 7:\n            mv = Wildfire_Future;\n            break;\n        default:\n            mv = Wildfire_Future;\n            break;\n        }\n\n        return mv;\n    }\n    \n    public static MqttVersion fromProtocolLevel(int protocolLevel) {\n        for (MqttVersion mv : values()) {\n            if (mv.level == (byte )protocolLevel) {\n                return mv;\n            }\n        }\n        if(protocolLevel > Wildfire_Future.level) {\n            return Wildfire_Future;\n        }\n        throw new MqttUnacceptableProtocolVersionException(protocolLevel + \"is unknown protocol level\");\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/io/netty/handler/codec/mqtt/package-info.java",
    "content": "/*\n * Copyright 2014 The Netty Project\n *\n * The Netty Project licenses this file to you under the Apache License, version 2.0 (the\n * \"License\"); you may not use this file except in compliance with the License. You may obtain a\n * copy of the License at:\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under the License\n * is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express\n * or implied. See the License for the specific language governing permissions and limitations under\n * the License.\n */\n\n/**\n * Encoder, decoder and different Message Types for MQTT.\n */\npackage io.netty.handler.codec.mqtt;\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/DBUtil.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage win.liyufan.im;\n\n\nimport java.beans.PropertyVetoException;\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.math.BigInteger;\nimport java.sql.*;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\n\nimport com.hazelcast.util.StringUtil;\nimport com.mchange.v2.c3p0.ComboPooledDataSource;\nimport io.moquette.BrokerConstants;\nimport io.moquette.server.config.IConfig;\nimport org.flywaydb.core.Flyway;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.concurrent.ConcurrentHashMap;\n\nimport static cn.wildfirechat.common.IMExceptionEvent.EventType.RDBS_Exception;\n\npublic class DBUtil {\n    private static final Logger LOG = LoggerFactory.getLogger(DBUtil.class);\n    private static ComboPooledDataSource comboPooledDataSource = null;\n    private static ConcurrentHashMap<Long, String>map = new ConcurrentHashMap<>();\n    private static ThreadLocal<Connection> transactionConnection = new ThreadLocal<Connection>() {\n        @Override\n        protected Connection initialValue() {\n            super.initialValue();\n            return null;\n        }\n    };\n\n    public static boolean IsEmbedDB = false;\n    public static boolean SystemExiting = false;\n    public static boolean ClearDBDebugMode = false;\n\n    public static void init(IConfig config) {\n        String embedDB = config.getProperty(BrokerConstants.EMBED_DB_PROPERTY_NAME);\n        String h2dbPath = config.getProperty(BrokerConstants.H2DB_PATH, \"./h2db/wfchat\");\n        boolean autoCleanMsgs = \"true\".equals(config.getProperty(BrokerConstants.DB_AUTO_CLEAN_HISTORY_MESSAGES));\n        if (embedDB != null && embedDB.equals(\"1\")) {\n            IsEmbedDB = true;\n            LOG.info(\"Use h2 database\");\n            String warning = \"您正在使用h2数据库，建议仅在开发验证或者用户数小于100人时才使用此数据库。正式上线时建议切换到MySQL数据库。\";\n            System.out.println(warning);\n            LOG.warn(warning);\n        } else {\n            IsEmbedDB = false;\n            LOG.info(\"Use mysql database\");\n        }\n\n        if (comboPooledDataSource == null) {\n            String migrateLocation;\n            if (IsEmbedDB) {\n                migrateLocation = \"filesystem:./migrate/h2\";\n                comboPooledDataSource = new ComboPooledDataSource();\n\n                comboPooledDataSource.setJdbcUrl( \"jdbc:h2:\" + h2dbPath + \";AUTO_SERVER=TRUE;MODE=MySQL\" );\n                comboPooledDataSource.setUser(\"SA\");\n                comboPooledDataSource.setPassword(\"SA\");\n                comboPooledDataSource.setMinPoolSize(5);\n                comboPooledDataSource.setAcquireIncrement(5);\n                comboPooledDataSource.setMaxPoolSize(20);\n\n                comboPooledDataSource.setIdleConnectionTestPeriod(60 * 5);\n                comboPooledDataSource.setMinPoolSize(3);\n                comboPooledDataSource.setInitialPoolSize(3);\n\n                try {\n                    comboPooledDataSource.setDriverClass( \"org.h2.Driver\" ); //loads the jdbc driver\n                } catch (PropertyVetoException e) {\n                    e.printStackTrace();\n                    Utility.printExecption(LOG, e);\n                    System.exit(-1);\n                }\n            } else {\n                migrateLocation = \"filesystem:./migrate/mysql\";\n                comboPooledDataSource = new ComboPooledDataSource(\"mysql\");\n                try {\n                    String url01 = comboPooledDataSource.getJdbcUrl().substring(0,comboPooledDataSource.getJdbcUrl().indexOf(\"?\"));\n                    String datasourceName = url01.substring(url01.lastIndexOf(\"/\")+1);\n                    // 连接已经存在的数据库，如：mysql\n                    String jdbc = comboPooledDataSource.getJdbcUrl().replace(datasourceName, \"\");\n                    Connection connection = DriverManager.getConnection(jdbc, comboPooledDataSource.getUser(), comboPooledDataSource.getPassword());\n                    Statement statement = connection.createStatement();\n\n                    // 创建数据库\n                    statement.executeUpdate(\"CREATE DATABASE IF NOT EXISTS `\" + datasourceName + \"` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\");\n\n                    statement.close();\n                    connection.close();\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    System.exit(-1);\n                }\n\n            }\n\n            Flyway flyway = Flyway.configure().dataSource(comboPooledDataSource).locations(migrateLocation).baselineOnMigrate(true).load();\n            if(!IsEmbedDB) {\n                if(flyway.info().current() == null) {\n                    System.out.println(\"数据库执行初始化需要较长时间，可能长达数分钟或更长，请耐心等待，不要中断。。。\");\n                } else if(flyway.info().current().getVersion().getMajor().intValue() < 43) {\n                    System.out.println(\"数据库执行升级需要较长时间，可能长达数分钟或更长，请耐心等待，不要中断。。。\");\n                }\n\n                if(flyway.info().current() != null && flyway.info().current().getVersion().getMajor().intValue() < 55) {\n                    Connection connection = null;\n                    PreparedStatement statement = null;\n                    try {\n                        connection = getConnection();\n\n                        String sql = \"update flyway_schema_history set checksum = ? where version = ? and checksum = ?\";\n\n                        statement = connection.prepareStatement(sql);\n                        int index = 1;\n                        statement.setLong(index++, -931486413L);\n                        statement.setString(index++, \"3\");\n                        statement.setLong(index++, 478454046L);\n                        statement.executeUpdate();\n                    } catch (SQLException e) {\n                        Utility.printExecption(LOG, e, RDBS_Exception);\n                    } finally {\n                        DBUtil.closeDB(connection, statement);\n                    }\n                }\n            }\n            flyway.migrate();\n\n            if(autoCleanMsgs) {\n                cleanHistoryMsg();\n            }\n        }\n    }\n\n    private static void cleanHistoryMsg() {\n        new Thread(()->{\n            long usedTime = 0;\n            while (true) {\n                if(SystemExiting) {\n                    break;\n                }\n                try {\n                    long sleepTime;\n                    if(ClearDBDebugMode) {\n                        sleepTime = 60 * 1000 - usedTime;\n                    } else {\n                        sleepTime = 60 * 60 * 1000 - usedTime;\n                    }\n                    if(sleepTime < 0) {\n                        sleepTime = 5 * 1000;\n                    }\n\n                    Thread.sleep(sleepTime);\n                    LOG.info(\"Start clean history messages\");\n\n                    if(SystemExiting) {\n                        break;\n                    }\n                    long start = System.currentTimeMillis();\n                    if(IsEmbedDB) {\n                        clearH2DB();\n                    } else {\n                        clearMySQL();\n                    }\n                    usedTime = System.currentTimeMillis() - start;\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            }\n        }).start();\n    }\n    private static boolean sleep() {\n        if(SystemExiting)\n            return true;\n\n        try {\n            if(ClearDBDebugMode) {\n                Thread.sleep(500);\n            } else {\n                Thread.sleep(10000);\n            }\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        return SystemExiting;\n    }\n\n    private static long getMaxMidNeedClean() {\n        Calendar cal = Calendar.getInstance();\n        cal.setTime(new Date());\n        cal.add(Calendar.YEAR, -3);\n        cal.add(Calendar.DATE, 1);\n        return MessageShardingUtil.getMsgIdFromTimestamp(cal.getTimeInMillis());\n    }\n\n    private static void clearH2DB() {\n        clearOneTable(\"t_user_messages\");\n        if(sleep()) {\n            return;\n        }\n        clearOneTable(\"t_messages\");\n    }\n\n    private static void clearMySQL() {\n        for (int i = 0; i < 128; i++) {\n            clearOneTable(\"t_user_messages_\" + i);\n            if(sleep()) {\n                return;\n            }\n        }\n\n        String msgTableName = MessageShardingUtil.getMessageTable(MessageShardingUtil.getMsgIdFromTimestamp(System.currentTimeMillis()));\n        clearOneTable(msgTableName);\n    }\n\n    private static void clearOneTable(String tableName) {\n        Connection connection = null;\n        PreparedStatement statement = null;\n        ResultSet rs = null;\n        long mid = getMaxMidNeedClean();\n\n        try {\n            connection = DBUtil.getConnection();\n            String sql = \"delete from \" + tableName + \" where _mid <= \" + mid;\n            statement = connection.prepareStatement(sql);\n            int count = statement.executeUpdate();\n            LOG.info(\"Delete history message {} rows\", count);\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e, RDBS_Exception);\n        } finally {\n            DBUtil.closeDB(connection, statement, rs);\n        }\n    }\n\n    private static List<String> getCreateSql() {\n        List<String> out = new ArrayList<>();\n        try{\n            BufferedReader br = new BufferedReader(new FileReader(\"h2/create_table.sql\"));//构造一个BufferedReader类来读取文件\n            String s = null;\n            StringBuilder result = new StringBuilder();\n            while((s = br.readLine())!=null) {\n                result.append(s);\n                if (s.contains(\";\")) {\n                    out.add(result.toString());\n                    result = new StringBuilder();\n                }\n            }\n            br.close();\n        }catch(Exception e){\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n        return out;\n    }\n    //从数据源中获取数据库的连接\n    public static Connection getConnection() throws SQLException {\n        long threadId = Thread.currentThread().getId();\n\n        if (map.get(threadId) != null) {\n            LOG.error(\"error here!!!! DB connection not close correctly\");\n        }\n        map.put(threadId, Thread.currentThread().getStackTrace().toString());\n        Connection connection = transactionConnection.get();\n        if (connection != null) {\n            LOG.debug(\"Thread {} get db connection {}\", threadId, connection);\n            return connection;\n        }\n\n        connection = comboPooledDataSource.getConnection();\n        LOG.debug(\"Thread {} get db connection {}\", threadId, connection);\n        return connection;\n    }\n\n    public static void beginTransaction() {\n        try {\n            Connection connection = getConnection();\n            connection.setAutoCommit(false);\n            transactionConnection.set(connection);\n        } catch (SQLException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n    }\n\n    public static void commit() {\n        try {\n            Connection connection = transactionConnection.get();\n            if (connection != null) {\n                connection.commit();\n                connection.setAutoCommit(true);\n                transactionConnection.remove();\n            }\n        } catch (SQLException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n    }\n\n    public static void roolback() {\n        try {\n            Connection connection = transactionConnection.get();\n            if (connection != null) {\n                connection.rollback();\n                connection.setAutoCommit(true);\n                transactionConnection.remove();\n            };\n        } catch (SQLException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n    }\n\n    //释放资源，将数据库连接还给数据库连接池\n    public static void closeDB(Connection conn,PreparedStatement ps,ResultSet rs) {\n        LOG.debug(\"Thread {} release db connection {}\", Thread.currentThread().getId(), conn);\n        try {\n            if (rs!=null) {\n                rs.close();\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        try {\n            if (ps!=null) {\n                ps.close();\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        try {\n            if (conn!=null && transactionConnection.get() != conn) {\n                conn.close();\n                map.remove(Thread.currentThread().getId());\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n    }\n    //释放资源，将数据库连接还给数据库连接池\n    public static void closeDB(Connection conn, PreparedStatement ps) {\n        LOG.debug(\"Thread {} release db connection {}\", Thread.currentThread().getId(), conn);\n        try {\n            if (ps!=null) {\n                ps.close();\n            }\n        } catch (SQLException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n\n        try {\n            if (conn!=null && transactionConnection.get() != conn) {\n                conn.close();\n                map.remove(Thread.currentThread().getId());\n            }\n        } catch (SQLException e) {\n            e.printStackTrace();\n            Utility.printExecption(LOG, e);\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/FrequencyLimistCounter.java",
    "content": "package win.liyufan.im;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n\n/**\n * 频率限制计数器，由于线程并发问题，并不一定严格准确，但总体可用\n */\npublic class FrequencyLimistCounter {\n\n    private final Map<String, Integer> CACHE_MAP = new HashMap<>();\n    private final Map<String, Long> CACHE_TIME_MAP = new HashMap<>();\n\n    private long CACHE_HOLD_TIME = 5 * 1000;\n\n    private int FREQUENCY_LIMIT = 100;\n\n    private final SpinLock mLock = new SpinLock();\n\n\n    private long lastFullScanTime = System.currentTimeMillis();\n    //2个小时全部扫描一次\n    private static final long fullScanDuration = 2*60*60*1000;\n\n    public FrequencyLimistCounter(int limitTimeSec, int limitCount) {\n        this.CACHE_HOLD_TIME = limitTimeSec * 1000;\n        this.FREQUENCY_LIMIT = limitCount;\n    }\n\n    public FrequencyLimistCounter() {\n    }\n\n    /**\n     * 增加对象计数并返回是否超频\n     * @param cacheName\n     * @return ture 超频; false 不超频\n     */\n    public boolean increaseAndCheck(String cacheName) {\n        mLock.lock();\n        try {\n            tryFullScan();\n            Long cacheHoldTime = CACHE_TIME_MAP.get(cacheName);\n\n            if (cacheHoldTime != null && cacheHoldTime < System.currentTimeMillis()) {\n                CACHE_MAP.remove(cacheName);\n                CACHE_TIME_MAP.remove(cacheName);\n            }\n\n            Integer count = CACHE_MAP.get(cacheName);\n            if (count != null) {\n                CACHE_MAP.put(cacheName, ++count);\n            } else {\n                count = 0;\n                CACHE_MAP.put(cacheName, ++count);\n                CACHE_TIME_MAP.put(cacheName, (System.currentTimeMillis() + CACHE_HOLD_TIME));//缓存失效时间\n            }\n            if (count >= FREQUENCY_LIMIT) {\n                return true;\n            }\n            return false;\n\n        } finally {\n            mLock.unLock();\n        }\n    }\n\n    //去掉超时的数据，如果在一个低频使用的系统中，会残留大量超时无用的信息\n    private void tryFullScan() {\n        if (System.currentTimeMillis() - lastFullScanTime > fullScanDuration) {\n            lastFullScanTime = System.currentTimeMillis();\n            for (Map.Entry<String, Long> entry : CACHE_TIME_MAP.entrySet()\n                 ) {\n                if (entry.getValue() < lastFullScanTime) {\n                    CACHE_MAP.remove(entry.getKey());\n                    CACHE_TIME_MAP.remove(entry.getKey());\n                }\n            }\n        }\n    }\n    public static void main(String[] args) {\n        FrequencyLimistCounter counter = new FrequencyLimistCounter(5, 100);\n        String name = \"test\";\n\n        for (int i = 0; i < 50; i++) {\n            if(counter.increaseAndCheck(name)) {\n                System.out.println(\"test failure 1\");\n                System.exit(-1);\n            }\n        }\n\n        try {\n            Thread.sleep(3000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n\n\n        for (int i = 0; i < 49; i++) {\n            if(counter.increaseAndCheck(name)) {\n                System.out.println(\"test failure 2\");\n                System.exit(-1);\n            }\n        }\n\n        if(!counter.increaseAndCheck(name)) {\n            System.out.println(\"test failure 3\");\n            System.exit(-1);\n        }\n\n        try {\n            Thread.sleep(5*1000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n\n        for (int i = 0; i < 99; i++) {\n            if(counter.increaseAndCheck(name)) {\n                System.out.println(\"test failure 4\");\n                System.exit(-1);\n            }\n        }\n\n        try {\n            Thread.sleep(5*1000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n\n        for (int i = 0; i < 99; i++) {\n            if(counter.increaseAndCheck(name)) {\n                System.out.println(\"test failure 5\");\n                System.exit(-1);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/GitRepositoryState.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage win.liyufan.im;\n\nimport io.moquette.server.Server;\n\nimport java.io.*;\nimport java.util.Properties;\nimport java.util.UUID;\n\npublic class GitRepositoryState {\n    public final String tags;\n    public final String branch;\n    public final String dirty;\n    public final String remoteOriginUrl;\n\n    public final String commitId;\n    public final String commitIdAbbrev;\n    public final String describe;\n    public final String describeShort;\n    public final String commitUserName;\n    public final String commitUserEmail;\n    public final String commitMessageFull;\n    public final String commitMessageShort;\n    public final String commitTime;\n    public static final String globalLabel = UUID.randomUUID().toString();\n    public String label;\n    public final String closestTagName;\n    public final String closestTagCommitCount;\n\n    public final String buildUserName;\n    public final String buildUserEmail;\n    public final String buildTime;\n    public final String buildHost;\n    public final String buildVersion;\n    public final long runTime;\n\n\n    private GitRepositoryState(Properties properties) {\n        this.tags = String.valueOf(properties.get(\"git.tags\"));\n        this.branch = String.valueOf(properties.get(\"git.branch\"));\n        this.dirty = String.valueOf(properties.get(\"git.dirty\"));\n        this.remoteOriginUrl = String.valueOf(properties.get(\"git.remote.origin.url\"));\n\n        this.commitId = String.valueOf(properties.get(\"git.commit.id.full\")); // OR properties.get(\"git.commit.id\") depending on your configuration\n        this.commitIdAbbrev = String.valueOf(properties.get(\"git.commit.id.abbrev\"));\n        this.describe = String.valueOf(properties.get(\"git.commit.id.describe\"));\n        this.describeShort = String.valueOf(properties.get(\"git.commit.id.describe-short\"));\n        this.commitUserName = String.valueOf(properties.get(\"git.commit.user.name\"));\n        this.commitUserEmail = String.valueOf(properties.get(\"git.commit.user.email\"));\n        this.commitMessageFull = String.valueOf(properties.get(\"git.commit.message.full\"));\n        this.commitMessageShort = String.valueOf(properties.get(\"git.commit.message.short\"));\n        this.commitTime = String.valueOf(properties.get(\"git.commit.time\"));\n        this.closestTagName = String.valueOf(properties.get(\"git.closest.tag.name\"));\n        this.closestTagCommitCount = String.valueOf(properties.get(\"git.closest.tag.commit.count\"));\n\n        this.buildUserName = String.valueOf(properties.get(\"git.build.user.name\"));\n        this.buildUserEmail = String.valueOf(properties.get(\"git.build.user.email\"));\n        this.buildTime = String.valueOf(properties.get(\"git.build.time\"));\n        this.buildHost = String.valueOf(properties.get(\"git.build.host\"));\n        this.buildVersion = String.valueOf(properties.get(\"git.build.version\"));\n        this.runTime = Server.getServer().getRunTime();\n        this.label = globalLabel;\n    }\n\n    public static GitRepositoryState getGitRepositoryState() throws IOException {\n        Properties properties = new Properties();\n        try {\n            String configPath = System.getProperty(\"wildfirechat.path\", null);\n            File f = new File(configPath, \"config/git.properties\");\n            InputStream inputStream = new FileInputStream(f);\n            BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream));\n            properties.load(bf);\n        } catch (IOException e) {\n            \n        }\n        GitRepositoryState gitRepositoryState = new GitRepositoryState(properties);\n        return gitRepositoryState;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/GsonUtil.java",
    "content": "package win.liyufan.im;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\n\npublic class GsonUtil {\n    public static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/HttpUtils.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage win.liyufan.im;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport io.netty.util.internal.StringUtil;\nimport okhttp3.*;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.HttpStatus;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.impl.client.HttpClientBuilder;\nimport org.apache.http.params.CoreConnectionPNames;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.nio.charset.Charset;\n\n\npublic class HttpUtils {\n    private static final Logger LOG = LoggerFactory.getLogger(HttpUtils.class);\n    public static final MediaType JSON = MediaType.get(\"application/json; charset=utf-8\");\n    static private OkHttpClient client = new OkHttpClient();\n    public interface HttpCallback {\n        void onSuccess(String content);\n        void onFailure(int statusCode, String errorMessage);\n    }\n\n    public enum HttpPostType {\n        POST_TYPE_Push,\n        POST_TYPE_Grout_Event_Callback,\n        POST_TYPE_Grout_Member_Event_Callback,\n        POST_TYPE_User_Relation_Event_Callback,\n        POST_TYPE_User_Info_Event_Callback,\n        POST_TYPE_Channel_Info_Event_Callback,\n        POST_TYPE_Channel_Subscriber_Event_Callback,\n        POST_TYPE_Chatroom_Info_Event_Callback,\n        POST_TYPE_Chatroom_Member_Event_Callback,\n        POST_TYPE_Robot_Message_Callback,\n        POST_TYPE_Channel_Message_Callback,\n        POST_TYPE_Forward_Message_Callback,\n        POST_TYPE_User_Online_Event_Callback,\n        POST_TYPE_Server_Exception_Callback,\n        POST_TYPE_Forward_Recall_Callback;\n    }\n\n    public static void httpJsonPost(String url, String jsonStr, HttpPostType postType) {\n        httpJsonPost(url, jsonStr, null, postType);\n    }\n\n    public static void httpJsonPost(String url, String jsonStr, HttpCallback httpCallback, HttpPostType postType) {\n        //消息推送内容为 {\"sender\":\"uCGUxUaa\",\"senderName\":\"杨\",\"convType\":0,\"target\":\"usq7v7UU\",\"targetName\":\"鞋子\",\"userId\":\"usq7v7UU\",\"line\":0,\"cntType\":400,\"serverTime\":1610590766485,\"pushMessageType\":1,\"pushType\":2,\"pushContent\":\"\",\"pushData\":\"\",\"unReceivedMsg\":1,\"mentionedType\":0,\"packageName\":\"cn.wildfirechat.chat\",\"deviceToken\":\"AFoieP9P6u6CccIkRK23gRwUJWKqSkdiqnb-6gC1kL7Wv-9XNoEYBPU7VsINU_q8_WTKfafe35qWu7ya7Z-NmgOTX9XVW3A3zd6ilh--quj6ccINXRvVnh8QmI9QQ\",\"isHiddenDetail\":false,\"language\":\"zh\"}\n        //推送信息只打印前100个字符，防止敏感信息打印到日志中去。\n        LOG.info(\"POST to {} with data {}...\", url, jsonStr.substring(0, Math.min(jsonStr.length(), 100)));\n        if (StringUtil.isNullOrEmpty(url)) {\n            LOG.error(\"http post failure with empty url\");\n            return;\n        }\n\n        RequestBody body = RequestBody.create(JSON, jsonStr);\n        Request request = new Request.Builder()\n            .url(url)\n            .post(body)\n            .build();\n        client.newCall(request).enqueue(new Callback() {\n            @Override\n            public void onFailure(Call call, IOException e) {\n                String logText;\n                if(postType == HttpPostType.POST_TYPE_Push) {\n                    logText = \"Http请求到推送服务失败，请检查推送服务是否正在运行或者配置文件中推送服务地址是否正确。\";\n                } else if(postType == HttpPostType.POST_TYPE_Robot_Message_Callback) {\n                    logText = \"Http请求转发消息到机器人服务失败，请检查机器人服务是否部署且在机器人信息中的回调地址是否正确。\\n如果不需要机器人及机器人服务，请关掉应用服务中自动添加机器人好友和发送机器人欢迎语的代码，用户不给机器人发送消息就不会有转发请求了。\";\n                } else if(postType == HttpPostType.POST_TYPE_Channel_Message_Callback ||\n                    postType == HttpPostType.POST_TYPE_Channel_Subscriber_Event_Callback) {\n                    logText = \"Http请求到频道服务失败，请检查频道服务是否部署且在频道信息中的回调地址是否正确。\";\n                } else {\n                    logText = \"Http请求回调地址失败，请检查IM服务配置文件中对应的回调地址是否正确\";\n                }\n                System.out.println(logText);\n                e.printStackTrace();\n                LOG.error(logText);\n                LOG.error(\"POST to {} failed\", url);\n                if(httpCallback != null) {\n                    httpCallback.onFailure(-1, e.getMessage());\n                }\n            }\n\n            @Override\n            public void onResponse(Call call, Response response) throws IOException {\n                LOG.info(\"POST to {} success with response: {}\", url, response.body());\n                try {\n                    if(httpCallback != null) {\n                        int code = response.code();\n                        if(code == 200) {\n                            if(response.body() != null) {\n                                httpCallback.onSuccess(response.body().string());\n                            } else {\n                                httpCallback.onSuccess(null);\n                            }\n                        } else {\n                            httpCallback.onFailure(code, response.message());\n                        }\n                    }\n                    if (response.body() != null) {\n                        response.body().close();\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/IDUtils.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage win.liyufan.im;\n\nimport java.util.HashMap;\nimport java.util.HashSet;\n\npublic class IDUtils {\n    private static final int RADIX = 36;\n    private static final int IDLEN = 9;\n    private static final int[] FACTOR = {29,19,1,11,7,17,13,23,5};\n\n    private static char getChar(long number) {\n        if (number < 26) {\n            return (char)('a' + number);\n        } else {\n            return (char)('0' + number - 26);\n        }\n    }\n\n    public static String toUid(long id) {\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < IDLEN; i++) {\n            long bit = ((id % RADIX) * FACTOR[i] + FACTOR[i] + 5)%RADIX;\n            sb.append(getChar(bit));\n            id = id / RADIX;\n        }\n        return sb.toString();\n    }\n    \n    public static void main(String[] args) {\n        HashSet<String> idset = new HashSet<>();\n        for (long i = 0; i < 1000000000000L; i++) {\n            String uid = toUid(i);\n            if(!idset.add(uid)) {\n                System.out.println(\"error, dupliate id\");\n                System.exit(-1);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/IMTopic.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage win.liyufan.im;\n\npublic interface IMTopic {\n\tString SendMessageTopic = \"MS\";\n    String RobotReplyMessageTopic = \"RRM\";\n    String MultiCastMessageTopic = \"MMC\";\n    String RecallMessageTopic = \"MR\";\n    String RecallMultiCastMessageTopic = \"MRMC\";\n\tString PullMessageTopic = \"MP\";\n\tString NotifyMessageTopic = \"MN\";\n    String NotifyRecallMessageTopic = \"RMN\";\n    String NotifyOffline = \"ROFL\";\n\n    String BroadcastMessageTopic = \"MBC\";\n\n    String GetUserSettingTopic = \"UG\";\n    String PutUserSettingTopic = \"UP\";\n    String NotifyUserSettingTopic = \"UN\";\n\n    String CreateGroupTopic = \"GC\";\n\tString AddGroupMemberTopic = \"GAM\";\n\tString KickoffGroupMemberTopic = \"GKM\";\n\tString QuitGroupTopic = \"GQ\";\n\tString DismissGroupTopic = \"GD\";\n\tString ModifyGroupInfoTopic = \"GMI\";\n    String ModifyGroupAliasTopic = \"GMA\";\n    String ModifyGroupMemberAliasTopic = \"GMMA\";\n    String ModifyGroupMemberExtraTopic = \"GMME\";\n    String GetGroupInfoTopic = \"GPGI\";\n    String GetGroupMemberTopic = \"GPGM\";\n    String TransferGroupTopic = \"GTG\";\n    String SetGroupManagerTopic = \"GSM\";\n    String GetMyGroupsTopic = \"GMGS\";\n    String GetCommonGroupsTopic = \"GCGS\";\n\n    String GetUserInfoTopic = \"UPUI\";\n    String ModifyMyInfoTopic = \"MMI\";\n    String NotifyUserInfoTopic = \"UIN\";\n\n\tString GetQiniuUploadTokenTopic = \"GQNUT\";\n\n    String AddFriendRequestTopic = \"FAR\";\n    String HandleFriendRequestTopic = \"FHR\";\n    String FriendRequestPullTopic = \"FRP\";\n    String NotifyFriendRequestTopic = \"FRN\";\n    String RriendRequestUnreadSyncTopic = \"FRUS\";\n    String SetFriendExtraTopic = \"FES\";\n\n    String DeleteFriendTopic = \"FDL\";\n    String FriendPullTopic = \"FP\";\n    String NotifyFriendTopic = \"FN\";\n    String BlackListUserTopic = \"BLU\";\n    String SetFriendAliasTopic = \"FALS\";\n\n\n    String UploadDeviceTokenTopic = \"UDT\";\n\n    String UserSearchTopic = \"US\";\n\n    String JoinChatroomTopic = \"CRJ\";\n    String QuitChatroomTopic = \"CRQ\";\n    String GetChatroomInfoTopic = \"CRI\";\n    String GetChatroomMemberTopic = \"CRMI\";\n\n    String RouteTopic = \"ROUTE\";\n\n    String CreateChannelTopic = \"CHC\";\n    String ModifyChannelInfoTopic = \"CHMI\";\n    String TransferChannelInfoTopic = \"CHT\";\n    String DestroyChannelInfoTopic = \"CHD\";\n    String ChannelSearchTopic = \"CHS\";\n    String ChannelListenTopic = \"CHL\";\n    String ChannelPullTopic = \"CHP\";\n    String ListenedChannelListTopic = \"CHLL\";\n\n    String GetTokenTopic = \"GETTOKEN\";\n    String DestroyUserTopic = \"DESTROYUSER\";\n\n    String LoadRemoteMessagesTopic = \"LRM\";\n    String KickoffPCClientTopic = \"KPCC\";\n\n    String ClearSessionTopic = \"CST\";\n\n    String GetApplicationTokenRequestTopic = \"ATR\";\n    String ApplicationConfigRequestTopic = \"ACR\";\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/MessageBundle.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage win.liyufan.im;\n\nimport cn.wildfirechat.proto.WFCMessage;\n\nimport java.io.Serializable;\n\n\npublic class MessageBundle implements Serializable {\n\t/**\n\t * \n\t */\n\tprivate static final long serialVersionUID = -8959293027687263752L;\n\tprivate String fromUser;\n\tprivate String fromClientId;\n\tprivate int type;\n\tprivate int line;\n\tprivate String targetId;\n\tprivate WFCMessage.Message message;\n\tprivate long messageId;\n\n    public MessageBundle() {\n    }\n\n    public MessageBundle(long messageId, String fromUser, String fromClientId, WFCMessage.Message message) {\n\t\tsuper();\n\t\tthis.fromUser = fromUser;\n\t\tthis.fromClientId = fromClientId;\n\t\tthis.type = message.getConversation().getType();\n\t\tthis.targetId = message.getConversation().getTarget();\n\t\tthis.line = message.getConversation().getLine();\n\t\tthis.message = message;\n\t\tthis.messageId = messageId;\n\t}\n\t\n\tpublic int getLine() {\n\t\treturn line;\n\t}\n\n\tpublic long getMessageId() {\n\t\treturn messageId;\n\t}\n\n\tpublic String getFromUser() {\n\t\treturn fromUser;\n\t}\n\tpublic String getFromClientId() {\n\t\treturn fromClientId;\n\t}\n\tpublic int getType() {\n\t\treturn type;\n\t}\n\tpublic String getTargetId() {\n\t\treturn targetId;\n\t}\n\tpublic WFCMessage.Message getMessage() {\n\t\treturn message;\n\t}\n\n    public void setFromClientId(String fromClientId) {\n        this.fromClientId = fromClientId;\n    }\n\n    public void setMessage(WFCMessage.Message message) {\n        this.fromUser = message.getFromUser();\n        this.type = message.getConversation().getType();\n        this.targetId = message.getConversation().getTarget();\n        this.line = message.getConversation().getLine();\n        this.message = message;\n        this.messageId = message.getMessageId();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/MessageShardingUtil.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage win.liyufan.im;\n\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class MessageShardingUtil {\n    private static SpinLock mLock = new SpinLock();\n    private static volatile int rotateId = 0;\n    private static volatile long timeId = 0;\n    private static int nodeId = 0;\n\n    private static int rotateIdWidth = 15;\n    private static int rotateIdMask = 0x7FFF;\n\n    private static int nodeIdWidth = 6;\n    private static int nodeIdMask = 0x3F;\n\n    private static final long T201801010000 = 1514736000000L;\n\n    public static void setNodeId(int nodeId) {\n        MessageShardingUtil.nodeId = nodeId;\n    }\n\n    /**\n     * ID = timestamp(43) + nodeId(6) + rotateId(15)\n     * 所以时间限制是到2157/5/15（2的42次幂代表的时间 + (2018-1970)）。节点数限制是小于64，每台服务器每毫秒最多发送32768条消息\n     * @return\n     */\n    public static long generateId() throws Exception {\n        mLock.lock();\n\n        rotateId = (rotateId + 1)&rotateIdMask;\n        long id = System.currentTimeMillis() - T201801010000;\n\n        if (id > timeId) {\n            timeId = id;\n            rotateId = 1;\n        } else if(id == timeId) {\n            if (rotateId == (rotateIdMask - 1)) { //当前空间已经用完，等待下一个空间打开\n                while (id <= timeId) {\n                    id = System.currentTimeMillis() - T201801010000;\n                }\n                mLock.unLock();\n                return generateId();\n            }\n        } else { //id < timeId;\n            if (rotateId > (rotateIdMask -1)*9/10) { //空间已经接近用完\n                if (timeId - id < 3000) { //时间回拨小于3秒，等待时间赶上回拨之前记录\n                    while (id < timeId) {\n                        id = System.currentTimeMillis() - T201801010000;\n                    }\n                    mLock.unLock();\n                    return generateId();\n                } else { //时间回拨大于3秒，抛出异常，这段时间消息将不可用。\n                    mLock.unLock();\n                    throw new Exception(\"Time turn back \" + (timeId - id) + \" ms, it too long!!!\");\n                }\n            } else {\n                id = timeId;\n            }\n\n        }\n\n        id <<= nodeIdWidth;\n        id += (nodeId & nodeIdMask);\n\n        id <<= rotateIdWidth;\n        id += rotateId;\n\n        mLock.unLock();\n\n\n        return id;\n    }\n\n    public static String getMessageTable(long mid) {\n        if (DBUtil.IsEmbedDB) {\n            return \"t_messages\";\n        }\n\n        Calendar calendar = Calendar.getInstance();\n        if (mid != Long.MAX_VALUE && mid != 0) {\n            mid >>= (nodeIdWidth + rotateIdWidth);\n            Date date = new Date(mid + T201801010000);\n            calendar.setTime(date);\n        } else {\n            Date date = new Date(System.currentTimeMillis());\n            calendar.setTime(date);\n        }\n        int month = calendar.get(Calendar.MONTH);\n        int year = calendar.get(Calendar.YEAR);\n        year %= 3;\n        return \"t_messages_\" + (year * 12 + month);\n    }\n    static Calendar getCalendarFromMessageId(long mid) {\n        Calendar calendar = Calendar.getInstance();\n        if (mid != Long.MAX_VALUE && mid != 0) {\n            mid >>= (nodeIdWidth + rotateIdWidth);\n            Date date = new Date(mid + T201801010000);\n            calendar.setTime(date);\n        } else {\n            Date date = new Date(System.currentTimeMillis());\n            calendar.setTime(date);\n        }\n        return calendar;\n    }\n    public static long getMsgIdFromTimestamp(long timestamp) {\n        long id = timestamp - T201801010000;\n\n        id <<= rotateIdWidth;\n        id <<= nodeIdWidth;\n\n        return id;\n    }\n\n    public static String getPreviousMessageTable(long mid) {\n        return getMessageTable(mid, -1);\n    }\n\n    public static String getMessageTable(long mid, int offset) {\n        if (DBUtil.IsEmbedDB) {\n            return null;\n        }\n\n        mid >>= (nodeIdWidth + rotateIdWidth);\n        Date date = new Date(mid + T201801010000);\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTime(date);\n        int month = calendar.get(Calendar.MONTH);\n        int year = calendar.get(Calendar.YEAR);\n        year %= 3;\n\n        month = month + offset;\n        while (month < 0) {\n            month += 12;\n            year = (year + 3 - 1)%3;\n        }\n        while (month >= 12) {\n            month -= 12;\n            year = (year + 1)%3;\n        }\n\n        return \"t_messages_\" + (year * 12 + month);\n    }\n\n    public static void main(String[] args) throws Exception {\n        ConcurrentHashMap<Long, Integer> messageIds = new ConcurrentHashMap<>();\n\n        int threadCount = 1000;\n        int loop = 1000000;\n        for (int i = 0; i < threadCount; i++) {\n            new Thread(()->{\n                for (int j = 0; j < loop; j++) {\n                    try {\n                        long mid = generateId();\n                        if(messageIds.put(mid, j) != null) {\n                            System.out.println(\"Duplicated message id !!!!!!\" + mid);\n                        }\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                    }\n                }\n            }).start();\n        }\n\n        Thread.sleep(1000 * 60 * 10);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/RateLimiter.java",
    "content": "package win.liyufan.im;\n\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\n\n/**\n * 漏桶算法\n * capacity * 1000是为了更精确, 漏水的小洞更小^~^\n */\npublic class RateLimiter {\n    private static final int DEFAULT_LIMIT_TIME_SECOND = 5;\n    private static final int DEFAULT_LIMIT_COUNT = 100;\n    private static final long expire = 2 * 60 * 60 * 1000;\n    private double rate = (double) DEFAULT_LIMIT_COUNT / (DEFAULT_LIMIT_TIME_SECOND);\n    private long capacity = DEFAULT_LIMIT_COUNT * 1000;\n    private long lastCleanTime;\n    private Map<String, Long> requestCountMap = new HashMap<>();\n    private Map<String, Long> requestTimeMap = new HashMap<>();\n\n    private SpinLock lock = new SpinLock();\n\n    public RateLimiter() {\n\n    }\n\n    public RateLimiter(int limitTimeSecond, int limitCount) {\n        if (limitTimeSecond <= 0 || limitCount <= 0) {\n            throw new IllegalArgumentException();\n        }\n        this.capacity = limitCount * 1000;\n        this.rate = (double) limitCount / limitTimeSecond;\n    }\n\n    /**\n     * 漏桶算法，https://en.wikipedia.org/wiki/Leaky_bucket\n     */\n    public boolean isGranted(String userId) {\n        try {\n            lock.lock();\n            long current = System.currentTimeMillis();\n            cleanUp(current);\n            Long lastRequestTime = requestTimeMap.get(userId);\n            long count = 0;\n            if (lastRequestTime == null) {\n                count += 1000;\n                requestTimeMap.put(userId, current);\n                requestCountMap.put(userId, count);\n                return true;\n            } else {\n                count = requestCountMap.get(userId);\n                lastRequestTime = requestTimeMap.get(userId);\n                count -= (current - lastRequestTime) * rate;\n                count = count > 0 ? count : 0;\n                requestTimeMap.put(userId, current);\n                if (count < capacity) {\n                    count += 1000;\n                    requestCountMap.put(userId, count);\n                    return true;\n                } else {\n                    requestCountMap.put(userId, count);\n                    return false;\n                }\n            }\n        } finally {\n            lock.unLock();\n        }\n    }\n\n    private void cleanUp(long current) {\n        if (current - lastCleanTime > expire) {\n            for (Iterator<Map.Entry<String, Long>> it = requestTimeMap.entrySet().iterator(); it.hasNext();) {\n                Map.Entry<String, Long> entry = it.next();\n                if (entry.getValue() < current - expire) {\n                    it.remove();\n                    requestCountMap.remove(entry.getKey());\n                }\n            }\n            lastCleanTime = current;\n        }\n    }\n\n    public static void main(String[] args) throws InterruptedException {\n        RateLimiter limiter = new RateLimiter(1, 10);\n        long start = System.currentTimeMillis();\n        for (int i = 0; i < 53; i++) {\n            if (!limiter.isGranted(\"test\")) {\n                System.out.println(\"1 too frequency \" + i);\n            }\n        }\n        Thread.sleep(1 * 1000);\n        System.out.println(\"sleep 1 s\");\n        for (int i = 0; i < 53; i++) {\n            if (!limiter.isGranted(\"test\")) {\n                System.out.println(\"2 too frequency \" + i);\n            }\n        }\n\n        Thread.sleep(5 * 1000);\n        System.out.println(\"sleep 5 s\");\n        for (int i = 0; i < 53; i++) {\n            if (!limiter.isGranted(\"test\")) {\n                System.out.println(\"3 too frequency \" + i);\n            }\n        }\n\n        Thread.sleep(5 * 1000);\n        System.out.println(\"sleep 5 s\");\n        long second = System.currentTimeMillis();\n        for (int i = 0; i < 100; i++) {\n            if (!limiter.isGranted(\"test\")) {\n                System.out.println(\"4 too frequency \" + i);\n            }\n            Thread.sleep(50);\n        }\n        System.out.println(\"second: \" + (System.currentTimeMillis() - second));\n        System.out.println(\"end: \" + (System.currentTimeMillis() - start));\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/SensitiveFilter.java",
    "content": "package win.liyufan.im;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\n\npublic class SensitiveFilter {\n    private static final Logger LOG = LoggerFactory.getLogger(SensitiveFilter.class);\n    public enum MatchType {\n        MIN_MATCH(\"最小匹配规则\"),MAX_MATCH(\"最大匹配规则\");\n\n        String desc;\n        MatchType(String desc) {\n            this.desc = desc;\n        }\n    }\n\n    private Map<Object,Object> sensitiveWordsMap;\n\n    private static final String END_FLAG=\"end\";\n\n    public boolean isContainSensitiveWord(String text){\n        Set<String> sensitiveWords = getSensitiveWords(text, MatchType.MIN_MATCH);\n        if(sensitiveWords!=null&&sensitiveWords.size()>0){\n            return true;\n        }\n        return false;\n    }\n\n    private int getUrlLength(String text, int i) {\n        boolean startUrl = false;\n        if(text.charAt(i) == 'h') {\n            if(text.length() > i + 6 && text.substring(i, i+7).equals(\"http://\")) {\n                startUrl = true;\n            } else if(text.length() > i + 7 && text.substring(i, i+8).equals(\"https://\")) {\n                startUrl = true;\n            }\n        }\n\n        if(startUrl) {\n            for (int j = i+1; j < text.length(); j++) {\n                char ch = text.charAt(j);\n                if(ch == ' ' || ch == '\\n' || ch == '\\r' || ch == '\\t') {\n                    return j-i;\n                }\n            }\n            return text.length() - i - 1;\n        }\n        return 0;\n    }\n\n    public Set<String> getSensitiveWords(String text,MatchType matchType){\n        Set<String> sensitiveWords=new HashSet<>();\n        if(text==null||text.trim().length()==0){\n            return sensitiveWords;\n        }\n\n        String originalText = text;\n        text = text.toLowerCase();\n        for(int i=0;i<text.length();i++){\n            int urlLength = getUrlLength(text, i);\n            if(urlLength > 0) {\n                i = i + urlLength;\n                continue;\n            }\n            int sensitiveWordLength = getSensitiveWordLength(text, i, matchType);\n            if(sensitiveWordLength>0){\n                String sensitiveWord = originalText.substring(i, i + sensitiveWordLength);\n                sensitiveWords.add(sensitiveWord);\n                if(matchType==MatchType.MIN_MATCH){\n                    break;\n                }\n                i=i+sensitiveWordLength-1;\n            }\n        }\n        if(!sensitiveWords.isEmpty()) {\n            LOG.info(\"Text {} matched sensitive word {}\", originalText, sensitiveWords);\n        }\n        return sensitiveWords;\n    }\n\n    public int getSensitiveWordLength(String text,int startIndex,MatchType matchType){\n        if(text==null||text.trim().length()==0){\n            throw new IllegalArgumentException(\"The input text must not be empty.\");\n        }\n        char currentChar;\n        Map<Object,Object> currentMap=sensitiveWordsMap;\n        int wordLength=0;\n        boolean endFlag=false;\n        for(int i=startIndex;i<text.length();i++){\n            currentChar=text.charAt(i);\n            Map<Object,Object> subMap=(Map<Object,Object>) currentMap.get(currentChar);\n            if(subMap==null){\n                break;\n            }else {\n                wordLength++;\n                if(subMap.containsKey(END_FLAG)){\n                    endFlag=true;\n                    if(matchType==MatchType.MIN_MATCH){\n                        break;\n                    }else {\n                        currentMap=subMap;\n                    }\n                }else {\n                    currentMap=subMap;\n                }\n            }\n        }\n        if(!endFlag){\n            wordLength=0;\n        }\n        return wordLength;\n    }\n\n\n    public SensitiveFilter(Set<String> sensitiveWords){\n        sensitiveWordsMap=new ConcurrentHashMap<>(sensitiveWords.size());\n        if(sensitiveWords==null||sensitiveWords.isEmpty()){\n            //throw new IllegalArgumentException(\"Senditive words must not be empty!\");\n            return;\n        }\n\n        String currentWord;\n        Map<Object,Object> currentMap;\n        Map<Object,Object> subMap;\n        Iterator<String> iterator = sensitiveWords.iterator();\n        while (iterator.hasNext()){\n            currentWord=iterator.next();\n            if(currentWord==null||currentWord.trim().length()<1){  //敏感词长度必须大于等于1\n                continue;\n            }\n            currentMap=sensitiveWordsMap;\n            for(int i=0;i<currentWord.length();i++){\n                char c=currentWord.charAt(i);\n                subMap=(Map<Object, Object>) currentMap.get(c);\n                if(subMap==null){\n                    subMap=new HashMap<>();\n                    currentMap.put(c,subMap);\n                    currentMap=subMap;\n                }else {\n                    currentMap= subMap;\n                }\n                if(i==currentWord.length()-1){\n                    //如果是最后一个字符，则put一个结束标志，这里只需要保存key就行了，value为null可以节省空间。\n                    //如果不是最后一个字符，则不需要存这个结束标志，同样也是为了节省空间。\n                    currentMap.put(END_FLAG,null);\n                }\n            }\n        }\n    }\n\n    public static void main(String[] args) {\n        Set<String> words = new HashSet<>();\n        words.add(\"sb\");\n        words.add(\"xx\");\n        SensitiveFilter sensitiveFilter = new SensitiveFilter(words);\n        String text1 = \"u sb a\";\n        Set<String> ss = sensitiveFilter.getSensitiveWords(text1, MatchType.MIN_MATCH);\n        System.out.println(ss.size());\n\n        text1 = \"u xx\";\n        ss = sensitiveFilter.getSensitiveWords(text1, MatchType.MIN_MATCH);\n        System.out.println(ss.size());\n\n        text1 = \"a  url is https://sdsbhe.com here\";\n        ss = sensitiveFilter.getSensitiveWords(text1, MatchType.MIN_MATCH);\n        System.out.println(ss.size());\n\n        text1 = \"a  url is https://sdsbhe.com\";\n        ss = sensitiveFilter.getSensitiveWords(text1, MatchType.MIN_MATCH);\n        System.out.println(ss.size());\n\n        text1 = \"a  url is https://sdsbhe.com\\nsb\";\n        ss = sensitiveFilter.getSensitiveWords(text1, MatchType.MIN_MATCH);\n        System.out.println(ss.size());\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/SpinLock.java",
    "content": "package win.liyufan.im;\n\nimport java.util.concurrent.atomic.AtomicReference;\n\npublic class SpinLock {\n    //java中原子（CAS）操作\n    AtomicReference<Thread> owner = new AtomicReference<>();//持有自旋锁的线程对象\n    private int count;\n    public void lock() {\n        Thread cur = Thread.currentThread();\n        //lock函数将owner设置为当前线程，并且预测原来的值为空。unlock函数将owner设置为null，并且预测值为当前线程。当有第二个线程调用lock操作时由于owner值不为空，导致循环\n\n        //一直被执行，直至第一个线程调用unlock函数将owner设置为null，第二个线程才能进入临界区。\n        while (!owner.compareAndSet(null, cur)){\n        }\n    }\n    public void unLock() {\n        Thread cur = Thread.currentThread();\n        owner.compareAndSet(cur, null);\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/UUIDGenerator.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage win.liyufan.im;\n\nimport java.util.UUID;\n\npublic class UUIDGenerator {\n\n    public static String getUUID() {\n        UUID uuid = UUID.randomUUID();\n        String str = uuid.toString();\n\n        str = str.replace(\"-\", \"\");\n        return str;\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/UserSettingScope.java",
    "content": "package win.liyufan.im;\n\npublic interface UserSettingScope {\n    int kUserSettingConversationSilent = 1;\n    int kUserSettingGlobalSilent = 2;\n    int kUserSettingHiddenNotificationDetail = 4;\n    int kUserSettingConversationSync = 7;\n    int kUserSettingMyChannels = 8;\n    int kUserSettingListenedChannels = 9;\n    int kUserSettingPCOnline = 10;\n    int kUserSettingMuteWhenPCOnline = 15;\n    int kUserSettingNoDisturbing = 17;\n    int kUserSettingConversationClearMessage = 18;\n    int kUserSettingConversationDraft = 19;\n    int kUserSettingDisableSyncDraft = 20;\n    int kUserSettingVoipSilent = 21;\n    int kUserSettingPttReserved = 22;\n    int kUserSettingCustomState = 23;\n    int kUserSettingDisableSecretChat = 24;\n    int kUserSettingPttSilent = 25;\n    int kUserSettingGroupRemark = 26;\n    int kUserSettingPrivacySearchable = 27;\n    int kUserSettingAddFriendStrategy = 28;\n    int kUserSettingScopeSyncBadge = 29;\n    int UserSettingScopeLockPC = 30;\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/Utility.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage win.liyufan.im;\n\nimport cn.wildfirechat.common.IMExceptionEvent;\nimport com.google.gson.Gson;\nimport com.hazelcast.util.StringUtil;\nimport io.moquette.server.Server;\nimport org.slf4j.Logger;\n\nimport java.net.*;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.AtomicLong;\n\npublic class Utility {\n    private static Map<String, IMExceptionEvent> exceptionEventHashMap = new ConcurrentHashMap<>();\n    static AtomicLong SendExceptionExpireTime = new AtomicLong(0);\n    static int SendExceptionDuration = 180000;\n    static long lastSendTime = System.currentTimeMillis();\n    static {\n        new Thread(()->{\n            while (true) {\n                try {\n                    Thread.sleep(60 * 1000);\n                    sendExceptionEvent();\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n\n            }\n        }).start();\n    }\n    public static InetAddress getLocalAddress(){\n        try {\n            Enumeration<NetworkInterface> b = NetworkInterface.getNetworkInterfaces();\n            while( b.hasMoreElements()){\n                for ( InterfaceAddress f : b.nextElement().getInterfaceAddresses())\n                    if ( f.getAddress().isSiteLocalAddress())\n                        return f.getAddress();\n            }\n        } catch (SocketException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    public static void printExecption(Logger LOG, Exception e) {\n        printExecption(LOG, e, 0);\n    }\n\n    public static void printExecption(Logger LOG, Exception e, int eventType) {\n        String message = \"\";\n\n        for(StackTraceElement stackTraceElement : e.getStackTrace()) {\n            message = message + System.lineSeparator() + stackTraceElement.toString();\n        }\n        LOG.error(\"Exception: {}\", e.getMessage());\n        LOG.error(message);\n        if(eventType > 0) {\n            String key = eventType+(e.getMessage() != null ? e.getMessage().split(\"\\n\")[0] : \"null\");\n            IMExceptionEvent event = exceptionEventHashMap.get(key);\n            if(event == null) {\n                event = new IMExceptionEvent();\n                event.event_type = eventType;\n                event.msg = e.getMessage();\n                event.call_stack = message;\n                event.count = 0;\n\n                exceptionEventHashMap.put(key, event);\n            }\n            event.count++;\n\n            sendExceptionEvent();\n        }\n    }\n\n    private static String gMonitorEventAddress;\n\n    public static void setMonitorEventAddress(String gMonitorEventAddress) {\n        Utility.gMonitorEventAddress = gMonitorEventAddress;\n    }\n\n    private static void sendExceptionEvent() {\n        if(StringUtil.isNullOrEmpty(gMonitorEventAddress)) {\n            return;\n        }\n\n        long now = System.currentTimeMillis();\n        long t = SendExceptionExpireTime.getAndUpdate((long l) -> now - l >= SendExceptionDuration ? now : l);\n\n        if(now - t >= SendExceptionDuration) {\n            for (Map.Entry<String, IMExceptionEvent> entry : exceptionEventHashMap.entrySet()) {\n                if(entry.getValue().count > 0) {\n                    String jsonStr = GsonUtil.gson.toJson(entry.getValue());\n                    Server.getServer().getCallbackScheduler().execute(() -> HttpUtils.httpJsonPost(gMonitorEventAddress, jsonStr, HttpUtils.HttpPostType.POST_TYPE_Server_Exception_Callback));\n                    entry.getValue().count = 0;\n                    lastSendTime = now;\n                }\n            }\n            if(now - lastSendTime > 24 * 3600 * 1000) {\n                lastSendTime = now;\n                IMExceptionEvent event = new IMExceptionEvent();\n                event.event_type = 0;\n                event.msg = \"监控心跳通知\";\n                event.call_stack = \"别担心！这个是心跳消息，已经有24小时没有出现异常消息了！\";\n                event.count = IMExceptionEvent.EventType.HEART_BEAT;\n                String jsonStr = GsonUtil.gson.toJson(event);\n                Server.getServer().getCallbackScheduler().execute(() -> HttpUtils.httpJsonPost(gMonitorEventAddress, jsonStr, HttpUtils.HttpPostType.POST_TYPE_Server_Exception_Callback));\n            }\n        }\n    }\n\n    public static String getMacAddress() throws UnknownHostException,\n        SocketException {\n        InetAddress ipAddress = InetAddress.getLocalHost();\n        NetworkInterface networkInterface = NetworkInterface\n            .getByInetAddress(ipAddress);\n        byte[] macAddressBytes = networkInterface.getHardwareAddress();\n        StringBuilder macAddressBuilder = new StringBuilder();\n\n        for (int macAddressByteIndex = 0; macAddressByteIndex < macAddressBytes.length; macAddressByteIndex++) {\n            String macAddressHexByte = String.format(\"%02X\",\n                macAddressBytes[macAddressByteIndex]);\n            macAddressBuilder.append(macAddressHexByte);\n\n            if (macAddressByteIndex != macAddressBytes.length - 1)\n            {\n                macAddressBuilder.append(\":\");\n            }\n        }\n\n        return macAddressBuilder.toString();\n    }\n\n    /**\n     * 格式化\n     *\n     * @param jsonStr\n     * @return\n     * @author lizhgb\n     * @Date 2015-10-14 下午1:17:35\n     * @Modified 2017-04-28 下午8:55:35\n     */\n    public static String formatJson(String jsonStr) {\n        if (null == jsonStr || \"\".equals(jsonStr))\n            return \"\";\n        StringBuilder sb = new StringBuilder();\n        char last = '\\0';\n        char current = '\\0';\n        int indent = 0;\n        boolean isInQuotationMarks = false;\n        for (int i = 0; i < jsonStr.length(); i++) {\n            last = current;\n            current = jsonStr.charAt(i);\n            switch (current) {\n                case '\"':\n                    if (last != '\\\\'){\n                        isInQuotationMarks = !isInQuotationMarks;\n                    }\n                    sb.append(current);\n                    break;\n                case '{':\n                case '[':\n                    sb.append(current);\n                    if (!isInQuotationMarks) {\n                        sb.append('\\n');\n                        indent++;\n                        addIndentBlank(sb, indent);\n                    }\n                    break;\n                case '}':\n                case ']':\n                    if (!isInQuotationMarks) {\n                        sb.append('\\n');\n                        indent--;\n                        addIndentBlank(sb, indent);\n                    }\n                    sb.append(current);\n                    break;\n                case ',':\n                    sb.append(current);\n                    if (last != '\\\\' && !isInQuotationMarks) {\n                        sb.append('\\n');\n                        addIndentBlank(sb, indent);\n                    }\n                    break;\n                default:\n                    sb.append(current);\n            }\n        }\n\n        return sb.toString();\n    }\n\n    /**\n     * 添加space\n     *\n     * @param sb\n     * @param indent\n     * @author lizhgb\n     * @Date 2015-10-14 上午10:38:04\n     */\n    private static void addIndentBlank(StringBuilder sb, int indent) {\n        for (int i = 0; i < indent; i++) {\n            sb.append('\\t');\n        }\n    }\n}\n"
  },
  {
    "path": "broker/src/main/java/win/liyufan/im/extended/mqttmessage/ModifiedMqttPubAckMessage.java",
    "content": "package win.liyufan.im.extended.mqttmessage;\n\nimport io.netty.buffer.ByteBuf;\nimport io.netty.handler.codec.mqtt.MqttFixedHeader;\nimport io.netty.handler.codec.mqtt.MqttMessage;\nimport io.netty.handler.codec.mqtt.MqttMessageIdVariableHeader;\n\npublic class ModifiedMqttPubAckMessage extends MqttMessage {\n    public ModifiedMqttPubAckMessage(MqttFixedHeader mqttFixedHeader, MqttMessageIdVariableHeader variableHeader, ByteBuf payload) {\n        super(mqttFixedHeader, variableHeader, payload);\n    }\n\n    @Override\n    public MqttMessageIdVariableHeader variableHeader() {\n        return (MqttMessageIdVariableHeader) super.variableHeader();\n    }\n}\n"
  },
  {
    "path": "broker/src/main/resources/c3p0-config.xml",
    "content": "<?xml version =\"1.0\" encoding=\"UTF-8\"?>\n\n<!--    # 本配置文件为debug使用，修改这里不会在Release包中生效。Release中包含的配置文件在 ${Porject_Path}/distribution/src/main/resources目录下-->\n\n<c3p0-config>\n    <!-- This is default config! -->\n    <default-config>\n        <property name=\"initialPoolSize\">10</property>\n        <property name=\"maxIdleTime\">30</property>\n        <property name=\"maxPoolSize\">100</property>\n        <property name=\"minPoolSize\">10</property>\n        <property name=\"maxStatements\">200</property>\n    </default-config>\n\n    <!-- This is my config for mysql-->\n    <named-config name=\"mysql\">\n        <!-- 指定数据库连接源的基本属性 -->\n        <!--MySQL数据库驱动程序-->\n        <property name=\"driverClass\">com.mysql.cj.jdbc.Driver</property>\n        <!--MySQL数据库地址-->\n        <property name=\"jdbcUrl\">jdbc:mysql://localhost:3306/wfchat?verifyServerCertificate=false&amp;useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true&amp;useUnicode=true&amp;characterEncoding=UTF-8</property>\n        <!--MySQL数据库用户名-->\n        <property name=\"user\">root</property>\n        <!--MySQL数据库密码-->\n        <property name=\"password\">123456</property>\n        <!-- 初始化连接池中的连接数，取值应在minPoolSize与maxPoolSize之间，默认为3-->\n        <property name=\"initialPoolSize\">10</property>\n        <!--最大空闲时间，60秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 -->\n        <property name=\"maxIdleTime\">30</property>\n        <!--连接池中保留的最大连接数。默认值: 15 -->\n        <property name=\"maxPoolSize\">100</property>\n        <!-- 连接池中保留的最小连接数，默认为：3-->\n        <property name=\"minPoolSize\">10</property>\n        <!--c3p0全局的PreparedStatements缓存的大小。如果maxStatements与maxStatementsPerConnection均为0，则缓存不生效，只要有一个不为0，则语句的缓存就能生效。如果默认值: 0-->\n        <property name=\"maxStatements\">200</property>\n        <!-- 当连接池连接耗尽时，客户端调用getConnection()后等待获取新连接的时间，超时后将抛出SQLException，如设为0则无限期等待。单位毫秒。默认: 0 -->\n        <property name=\"checkoutTimeout\">3000</property>\n        <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。默认值: 3 -->\n        <property name=\"acquireIncrement\">2</property>\n        <!--定义在从数据库获取新连接失败后重复尝试的次数。默认值: 30 ；小于等于0表示无限次-->\n        <property name=\"acquireRetryAttempts\">0</property>\n        <!--重新尝试的时间间隔，默认为：1000毫秒-->\n        <property name=\"acquireRetryDelay\">1000</property>\n        <!--关闭连接时，是否提交未提交的事务，默认为false，即关闭连接，回滚未提交的事务 -->\n        <property name=\"autoCommitOnClose\">false</property>\n        <!--c3p0将建一张名为Test的空表，并使用其自带的查询语句进行测试。如果定义了这个参数那么属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作，它将只供c3p0测试使用。默认值: null -->\n        <!--<property name=\"automaticTestTable\">null</property>-->\n        <!--如果为false，则获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常，但是数据源仍有效保留，并在下次调用getConnection()的时候继续尝试获取连接。如果设为true，那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。默认: false-->\n        <property name=\"breakAfterAcquireFailure\">false</property>\n        <!--每60秒检查所有连接池中的空闲连接。默认值: 0，不检查 -->\n        <property name=\"idleConnectionTestPeriod\">60</property>\n        <!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。默认值: 0 -->\n        <!--<property name=\"maxStatementsPerConnection\"></property>-->\n    </named-config>\n</c3p0-config>\n"
  },
  {
    "path": "broker/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->\n<!--status=\"WARN\" :用于设置log4j2自身内部日志的信息输出级别，默认是OFF-->\n<!--monitorInterval=\"30\"  :间隔秒数,自动检测配置文件的变更和重新配置本身-->\n<configuration status=\"WARN\" monitorInterval=\"60\">\n    <Properties>\n        <!--自定义一些常量，之后使用${变量名}引用-->\n        <Property name=\"MSG_LOG_HOME\">./logs</Property>\n        <property name=\"charset\">UTF-8</property>\n        <!--自定义的输出格式-->\n        <property name=\"pattern\">%d %-5p [%t] %C{2} (%F:%L) - %m%n</property>\n    </Properties>\n    <!--appenders:定义输出内容,输出格式,输出方式,日志保存策略等,常用其下三种标签[console,File,RollingFile]-->\n    <appenders>\n        <!--console :控制台输出的配置-->\n        <console name=\"Console\" target=\"SYSTEM_OUT\">\n            <!--PatternLayout :输出日志的格式,LOG4J2定义了输出代码,详见第二部分-->\n            <PatternLayout pattern=\"[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n\"/>\n        </console>\n\n        <RollingRandomAccessFile name=\"RollingFileInfo\" immediateFlush=\"false\"\n                                 fileName=\"${MSG_LOG_HOME}/wildfirechat.log\"\n                                 filePattern=\"${MSG_LOG_HOME}/backup/wildfirechat.%d{yyyyMMddHHmm}.zip\">\n            <Filters>\n                <ThresholdFilter level=\"INFO\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n            </Filters>\n            <PatternLayout pattern=\"${pattern}\" />\n            <Policies>\n                <!-- TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件,interval=\"6\" : 自定义文件滚动时间间隔,每隔6小时产生新文件, modulate=\"true\" : 产生文件是否以0点偏移时间,即6点,12点,18点,0点-->\n                <TimeBasedTriggeringPolicy interval=\"6\" modulate=\"true\"/>\n                <!-- SizeBasedTriggeringPolicy :文件大小滚动策略-->\n                <SizeBasedTriggeringPolicy size=\"100 MB\"/>\n            </Policies>\n\n            <DefaultRolloverStrategy max=\"24\">\n                <Delete basePath=\"${MSG_LOG_HOME}\" maxDepth=\"2\">\n                    <IfFileName glob=\"*/wildfirechat.*.zip\" />\n                    <IfLastModified age=\"24H\" />\n                </Delete>\n            </DefaultRolloverStrategy>\n        </RollingRandomAccessFile>\n\n        <RollingRandomAccessFile name=\"RollingFileWarn\" immediateFlush=\"true\"\n                                 fileName=\"${MSG_LOG_HOME}/wildfirechat_warn.log\"\n                                 filePattern=\"${MSG_LOG_HOME}/backup/wildfirechat_warn.%d{yyyyMMddHH}.zip\">\n            <Filters>\n                <ThresholdFilter level=\"WARN\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n            </Filters>\n            <PatternLayout pattern=\"${pattern}\" />\n            <Policies>\n                <!-- TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件,interval=\"6\" : 自定义文件滚动时间间隔,每隔6小时产生新文件, modulate=\"true\" : 产生文件是否以0点偏移时间,即6点,12点,18点,0点-->\n                <TimeBasedTriggeringPolicy interval=\"6\" modulate=\"true\"/>\n                <!-- SizeBasedTriggeringPolicy :文件大小滚动策略-->\n                <SizeBasedTriggeringPolicy size=\"100 MB\"/>\n            </Policies>\n\n            <DefaultRolloverStrategy max=\"24\">\n                <Delete basePath=\"${MSG_LOG_HOME}\" maxDepth=\"2\">\n                    <IfFileName glob=\"*/wildfirechat_warn.*.zip\" />\n                    <IfLastModified age=\"24H\" />\n                </Delete>\n            </DefaultRolloverStrategy>\n        </RollingRandomAccessFile>\n\n        <RollingRandomAccessFile name=\"RollingFileError\" immediateFlush=\"true\"\n                                 fileName=\"${MSG_LOG_HOME}/wildfirechat_error.log\"\n                                 filePattern=\"${MSG_LOG_HOME}/backup/wildfirechat_error.%d{yyyyMMddHH}.zip\">\n            <Filters>\n                <ThresholdFilter level=\"ERROR\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n            </Filters>\n            <PatternLayout pattern=\"${pattern}\" />\n            <Policies>\n                <!-- TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件,interval=\"6\" : 自定义文件滚动时间间隔,每隔6小时产生新文件, modulate=\"true\" : 产生文件是否以0点偏移时间,即6点,12点,18点,0点-->\n                <TimeBasedTriggeringPolicy interval=\"6\" modulate=\"true\"/>\n                <!-- SizeBasedTriggeringPolicy :文件大小滚动策略-->\n                <SizeBasedTriggeringPolicy size=\"100 MB\"/>\n            </Policies>\n\n            <DefaultRolloverStrategy max=\"24\">\n                <Delete basePath=\"${MSG_LOG_HOME}\" maxDepth=\"2\">\n                    <IfFileName glob=\"*/wildfirechat_error.*.zip\" />\n                    <IfLastModified age=\"24H\" />\n                </Delete>\n            </DefaultRolloverStrategy>\n        </RollingRandomAccessFile>\n    </appenders>\n\n    <!--然后定义logger，只有定义了logger并引入的appender，appender才会生效-->\n    <loggers>\n        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->\n        <!--Logger节点用来单独指定日志的形式，name为包路径,比如要为org.springframework包下所有日志指定为INFO级别等。 -->\n        <!--        <logger name=\"org.springframework\" level=\"INFO\"></logger>-->\n        <!--        <logger name=\"org.mybatis\" level=\"INFO\"></logger>-->\n        <!-- Root节点用来指定项目的根日志，如果没有单独指定Logger，那么就会默认使用该Root日志输出 -->\n        <root level=\"INFO\">\n            <appender-ref ref=\"Console\"/>\n            <appender-ref ref=\"RollingFileInfo\"/>\n            <appender-ref ref=\"RollingFileWarn\"/>\n            <appender-ref ref=\"RollingFileError\"/>\n        </root>\n        <!--AsyncLogger :异步日志,LOG4J有三种日志模式,全异步日志,混合模式,同步日志,性能从高到底,线程越多效率越高,也可以避免日志卡死线程情况发生-->\n        <!--additivity=\"false\" : additivity设置事件是否在root logger输出，为了避免重复输出，可以在Logger 标签下设置additivity为”false”-->\n        <AsyncLogger name=\"AsyncLogger\" level=\"trace\" includeLocation=\"true\" additivity=\"false\">\n            <appender-ref ref=\"RollingFileInfo\"/>\n        </AsyncLogger>\n    </loggers>\n</configuration>\n"
  },
  {
    "path": "build.sh",
    "content": "#!/bin/bash\n\nmvn clean compile package\n"
  },
  {
    "path": "checkstyle-suppressions.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE suppressions PUBLIC\n        \"-//Puppy Crawl//DTD Suppressions 1.0//EN\"\n        \"http://www.puppycrawl.com/dtds/suppressions_1_0.dtd\">\n\n<suppressions>\n    <suppress checks=\"[a-zA-Z0-9]*\" files=\".*/resources/.*\"/>\n</suppressions>\n"
  },
  {
    "path": "checkstyle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n  ~ Copyright 2012 The Netty Project\n  ~\n  ~ The Netty Project licenses this file to you under the Apache License,\n  ~ version 2.0 (the \"License\"); you may not use this file except in compliance\n  ~ with the License. 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, WITHOUT\n  ~ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n  ~ License for the specific language governing permissions and limitations\n  ~ under the License.\n  -->\n<!DOCTYPE module PUBLIC\n  \"-//Puppy Crawl//DTD Check Configuration 1.2//EN\"\n  \"http://www.puppycrawl.com/dtds/configuration_1_2.dtd\">\n<module name=\"Checker\">\n  <property name=\"severity\" value=\"warning\"/>\n\n  <!--\n  <module name=\"SuppressionFilter\">\n    <property name=\"file\" value=\"checkstyle-suppressions.xml\" />\n  </module>\n  <module name=\"io.netty.build.checkstyle.SuppressionFilter\">\n    <property name=\"pattern\" value=\"((LocalTime|WorldClock)Protocol|LinkedTransferQueue|Version|jzlib/.*|chmv8/.*|com/sun/nio/sctp/.*)\\.java\" />\n  </module>\n   -->\n  <module name=\"FileTabCharacter\"/>\n  <!--\n  <module name=\"JavadocPackage\"/>\n  -->\n  <module name=\"NewlineAtEndOfFile\">\n    <property name=\"lineSeparator\" value=\"lf\" />\n  </module>\n  <!-- Copyright headers -->\n  <module name=\"RegexpSingleline\">\n    <property name=\"format\" value=\"^(\\s|\\*)*Copyright\\s.*$\"/>\n    <property name=\"minimum\" value=\"1\"/>\n    <property name=\"maximum\" value=\"1\"/>\n    <property name=\"message\" value=\"missing copyright header\"/>\n  </module>\n  <!-- Unmaintainable Javadoc tags -->\n  <module name=\"RegexpSingleline\">\n    <property name=\"format\" value=\"(@(author|version)|\\(non-Javadoc\\))\"/>\n    <property name=\"ignoreCase\" value=\"true\"/>\n    <property name=\"message\" value=\"unmaintainable Javadoc tags: @author, @version, or (non-Javadoc)\"/>\n  </module>\n  <!-- IDE-generated comment -->\n  <module name=\"RegexpSingleline\">\n    <property name=\"format\" value=\"File \\| Settings \\| File Templates\"/>\n    <property name=\"message\" value=\"IDE-generated comment\"/>\n  </module>\n  <!-- Force UNIX line separator \n  <module name=\"io.netty.build.checkstyle.NewlineCheck\"/>\n  -->\n\n  <!-- Trailing whitespace -->\n  <module name=\"RegexpSingleline\">\n    <property name=\"format\" value=\"\\s+$\"/>\n    <property name=\"message\" value=\"trailing whitespace\"/>\n  </module> \n  <!-- Prohibit consecutive empty lines (except the lines after package/import) -->\n  <module name=\"RegexpMultiline\">\n    <property name=\"format\" value=\"\\n *(?!package )(?!import )[^\\n]+\\n{3,}\"/>\n    <property name=\"message\" value=\"two or more consecutive empty lines\"/>\n  </module>\n  <!-- Prohibit an empty after { or before } -->\n  <module name=\"RegexpMultiline\">\n    <property name=\"format\" value=\"\\n\\n\\s+\\}[^\\n]{0,10}\\n\"/>\n    <property name=\"message\" value=\"an empty line before '}'\"/>\n  </module>\n  <module name=\"RegexpMultiline\">\n    <property name=\"format\" value=\"\\n\\s+[^\\n]{1,8}\\{\\n\\n\"/>\n    <property name=\"message\" value=\"an empty line after a short line that ends with '{'\"/>\n  </module>\n\n  <module name=\"TreeWalker\">\n    <module name=\"LineLength\">\n      <property name=\"max\" value=\"120\"/>\n    </module>\n    <module name=\"WhitespaceAfter\"/>\n    <module name=\"WhitespaceAround\">\n      <property name=\"tokens\" value=\"ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, DIV, DIV_ASSIGN, EQUAL, GE, GT, LAND, LCURLY, LE, LITERAL_ASSERT, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, RCURLY, SL, SLIST, SL_ASSIGN, SR, SR_ASSIGN, STAR, STAR_ASSIGN, TYPE_EXTENSION_AND\"/>\n    </module>\n    <!-- Commented out due to false positives.\n    <module name=\"MissingDeprecated\"/>\n    -->\n    <module name=\"MissingOverride\"/>\n    <module name=\"PackageAnnotation\"/>\n    <module name=\"EmptyBlock\">\n      <property name=\"option\" value=\"text\"/>\n    </module>\n    <module name=\"LeftCurly\"/>\n    <module name=\"RightCurly\"/>\n    <!--\n    <module name=\"NeedBraces\"/>\n    -->\n    <module name=\"AvoidNestedBlocks\">\n      <property name=\"allowInSwitchCase\" value=\"true\"/>\n    </module>\n    <module name=\"FinalClass\"/>\n    <module name=\"HideUtilityClassConstructor\"/>\n    <module name=\"CovariantEquals\"/>\n    <module name=\"EmptyStatement\"/>\n    <module name=\"EqualsHashCode\"/>\n    <!--\n    <module name=\"FinalLocalVariable\"/>\n    -->\n    <!-- Commented out due to http://jira.codehaus.org/browse/MCHECKSTYLE-111\n    <module name=\"RedundantThrows\">\n      <property name=\"logLoadErrors\" value=\"false\"/>\n      <property name=\"suppressLoadErrors\" value=\"true\"/>\n    </module>\n    -->\n    <module name=\"SimplifyBooleanExpression\"/>\n    <module name=\"SimplifyBooleanReturn\"/>\n    <module name=\"SuperFinalize\"/>\n    <module name=\"PackageDeclaration\"/>\n    <module name=\"ExplicitInitialization\"/>\n    <module name=\"DefaultComesLast\"/>\n    <module name=\"UnnecessaryParentheses\"/>\n    <!--\n    <module name=\"AvoidStarImport\">\n      <property name=\"allowStaticMemberImports\" value=\"true\"/>\n    </module>\n    -->\n    <module name=\"RedundantImport\"/>\n    <!-- Commented out due to false positives.\n    <module name=\"UnusedImports\">\n      <property name=\"processJavadoc\" value=\"true\"/>\n    </module>\n    -->\n    <module name=\"JavadocStyle\">\n      <property name=\"checkFirstSentence\" value=\"false\"/>\n    </module>\n    <module name=\"UpperEll\"/>\n    <module name=\"ArrayTypeStyle\"/>\n    <module name=\"OuterTypeFilename\"/>\n    <module name=\"ModifierOrder\"/>\n    <module name=\"RedundantModifier\"/>\n    <module name=\"GenericWhitespace\"/>\n    <module name=\"EmptyForInitializerPad\"/>\n    <module name=\"EmptyForIteratorPad\"/>\n    <module name=\"MethodParamPad\"/>\n    <module name=\"ParenPad\"/>\n    <module name=\"TypecastParenPad\"/>\n    <module name=\"ParameterName\">\n      <property name=\"format\" value=\"^(?!arg[0-9])[_a-z][_a-zA-Z0-9]*$\" />\n    </module>\n  </module>\n</module>"
  },
  {
    "path": "common/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>wildfirechat-parent</artifactId>\n        <groupId>cn.wildfirechat</groupId>\n        <version>1.4.5</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>common</artifactId>\n\n    <dependencies>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-common</artifactId>\n            <version>${netty.version}</version>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->\n        <dependency>\n            <groupId>com.google.protobuf</groupId>\n            <artifactId>protobuf-java</artifactId>\n            <version>2.5.0</version>\n        </dependency>\n\n        <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->\n        <dependency>\n            <groupId>com.google.code.gson</groupId>\n            <artifactId>gson</artifactId>\n            <version>2.8.9</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.googlecode.json-simple</groupId>\n            <artifactId>json-simple</artifactId>\n            <version>1.1.1</version>\n        </dependency>\n    </dependencies>\n\n</project>\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/common/APIPath.java",
    "content": "package cn.wildfirechat.common;\n\n/**\n * API路径接口\n * <p>\n * 定义了野火IM服务器所有管理接口的API路径。\n * 包括聊天室、敏感词、域、用户、好友、黑名单、消息、群组、会议、频道等模块的接口路径。\n * </p>\n */\npublic interface APIPath {\n    String Create_Chatroom = \"/admin/chatroom/create\";\n    String Chatroom_Destroy = \"/admin/chatroom/del\";\n    String Chatroom_Info = \"/admin/chatroom/info\";\n    String Chatroom_GetMembers = \"/admin/chatroom/members\";\n    String Chatroom_GetUserChatroom = \"/admin/chatroom/user_chatroom\";\n    String Chatroom_SetBlacklist = \"/admin/chatroom/set_black_status\";\n    String Chatroom_GetBlacklist = \"/admin/chatroom/get_black_status\";\n    String Chatroom_SetManager = \"/admin/chatroom/set_manager\";\n    String Chatroom_GetManagerList = \"/admin/chatroom/get_manager_list\";\n    String Chatroom_MuteAll = \"/admin/chatroom/mute_all\";\n\n\n    String Sensitive_Add = \"/admin/sensitive/add\";\n    String Sensitive_Del = \"/admin/sensitive/del\";\n    String Sensitive_Query = \"/admin/sensitive/query\";\n\n    String Create_Domain = \"/admin/domain/create\";\n    String Get_Domain = \"/admin/domain/get\";\n    String Destroy_Domain = \"/admin/domain/destroy\";\n    String List_Domain = \"/admin/domain/list\";\n    String Ping_Domain = \"/admin/domain/ping\";\n\n    String Create_User = \"/admin/user/create\";\n    String Update_User = \"/admin/user/update\";\n    String Destroy_User = \"/admin/user/destroy\";\n    String Search_User = \"/admin/user/search_user\";\n    String Create_Robot = \"/admin/robot/create\";\n    String CreateOrUpdate_Device = \"/admin/device/create\";\n    String Get_Device = \"/admin/device/get\";\n    String Get_User_Devices = \"/admin/device/user_devices\";\n    String User_Get_Token = \"/admin/user/get_token\";\n    String User_Update_Block_Status = \"/admin/user/update_block_status\";\n    String User_Get_Info = \"/admin/user/get_info\";\n    String User_Batch_Get_Infos = \"/admin/user/batch_get_infos\";\n    String User_Get_Email_Info = \"/admin/user/get_info_by_email\";\n    String User_Get_All = \"/admin/user/all\";\n    String User_Get_Robot_Info = \"/admin/user/get_robot_info\";\n    String User_Get_User_Robots = \"/admin/user/get_user_robots\";\n    String User_Get_Blocked_List = \"/admin/user/get_blocked_list\";\n    String User_Check_Block_Status = \"/admin/user/check_block_status\";\n    String User_Get_Online_Status = \"/admin/user/onlinestatus\";\n    String User_Put_Setting = \"/admin/user/put_setting\";\n    String User_Get_Setting = \"/admin/user/get_setting\";\n    String User_Kickoff_Client = \"/admin/user/kickoff_client\";\n    String User_Online_Count = \"/admin/user/online_count\";\n    String User_Online_List = \"/admin/user/online_list\";\n    String User_Session_List = \"/admin/user/session_list\";\n    String User_Application_Get_UserInfo = \"/admin/user/app_get_user_info\";\n\n    String Friend_Update_Status = \"/admin/friend/status\";\n    String Friend_Get_List = \"/admin/friend/list\";\n    String Blacklist_Update_Status = \"/admin/blacklist/status\";\n    String Blacklist_Get_List = \"/admin/blacklist/list\";\n    String Friend_Get_Alias = \"/admin/friend/get_alias\";\n    String Friend_Set_Alias = \"/admin/friend/set_alias\";\n    String Friend_Set_Extra = \"/admin/friend/set_extra\";\n    String Friend_Send_Request = \"/admin/friend/send_request\";\n    String Friend_Get_Requests = \"/admin/friend/get_requests\";\n    String Relation_Get = \"/admin/relation/get\";\n\n    String Handle_Friend_Send_Request = \"/admin/friend/handle_send_request\";\n\n    String Admin_Moments_Post_Feed = \"/admin/moments/feed/post\";\n\n    String Msg_Send = \"/admin/message/send\";\n    String Msg_Publish = \"/admin/message/publish\";\n    String Msg_Recall = \"/admin/message/recall\";\n    String Msg_Delete = \"/admin/message/delete\";\n    String Msg_Update = \"/admin/message/update\";\n    String Msg_GetOne = \"/admin/message/get_one\";\n    String Msg_Broadcast = \"/admin/message/broadcast\";\n    String Msg_Multicast = \"/admin/message/multicast\";\n    String Msg_RecallBroadCast = \"/admin/message/recall_broadcast\";\n    String Msg_RecallMultiCast = \"/admin/message/recall_multicast\";\n    String Msg_DeleteBroadCast = \"/admin/message/delete_broadcast\";\n    String Msg_DeleteMultiCast = \"/admin/message/delete_multicast\";\n    String Msg_ConvRead = \"/admin/message/conv_read\";\n    String Msg_Delivery = \"/admin/message/delivery\";\n    String Conversation_Delete = \"/admin/conversation/delete\";\n    String Msg_Clear_By_User = \"/admin/message/clear_by_user\";\n\n    String Create_Group = \"/admin/group/create\";\n    String Group_Dismiss = \"/admin/group/del\";\n    String Group_Transfer = \"/admin/group/transfer\";\n    String Group_Get_Info = \"/admin/group/get_info\";\n    String Group_Batch_Info = \"/admin/group/batch_infos\";\n    String Group_Modify_Info = \"/admin/group/modify\";\n    String Group_Member_List = \"/admin/group/member/list\";\n    String Group_Member_Get = \"/admin/group/member/get\";\n    String Group_Member_Add = \"/admin/group/member/add\";\n    String Group_Member_Kickoff = \"/admin/group/member/del\";\n    String Group_Member_Quit = \"/admin/group/member/quit\";\n    String Group_Set_Manager = \"/admin/group/manager/set\";\n    String Group_Mute_Member = \"/admin/group/manager/mute\";\n    String Group_Allow_Member = \"/admin/group/manager/allow\";\n    String Group_Join_Request_Add = \"/admin/group/join_request/add\";\n    String Get_User_Groups = \"/admin/group/of_user\";\n    String Get_User_Groups_By_Type = \"/admin/group/of_user_by_type\";\n    String Group_Set_Member_Alias = \"/admin/group/member/set_alias\";\n    String Group_Set_Member_Extra = \"/admin/group/member/set_extra\";\n    String Get_Common_Groups = \"/admin/group/common_group\";\n\n    String Sync_Group = \"/admin/mesh/group_sync\";\n    String Conference_User_Request = \"/admin/conference/user_request\";\n    String Conference_User_Event = \"/admin/conference/user_event\";\n\n    String Create_Channel = \"/admin/channel/create\";\n    String Destroy_Channel = \"/admin/channel/destroy\";\n    String Get_Channel_Info = \"/admin/channel/get\";\n    String Subscribe_Channel = \"/admin/channel/subscribe\";\n    String Check_User_Subscribe_Channel = \"/admin/channel/is_subscribed\";\n    String Get_System_Setting = \"/admin/system/get_setting\";\n    String Put_System_Setting = \"/admin/system/put_setting\";\n    String GET_CUSTOMER = \"/admin/customer\";\n    String Health = \"/admin/health\";\n    String Get_Conversation_Files = \"/admin/file/conversation_files\";\n    String Get_User_Files = \"/admin/file/user_files\";\n    String Get_Message_File = \"/admin/file/message_file\";\n\n    String Get_Presigned_Upload_Url = \"/admin/oss/get_upload_url\";\n\n    String Conference_List = \"/admin/conference/list\";\n    String Conference_Exist = \"/admin/conference/exist\";\n    String Conference_List_Participant = \"/admin/conference/list_participant\";\n    String Conference_Create = \"/admin/conference/create\";\n    String Conference_Destroy = \"/admin/conference/destroy\";\n    String Conference_Recording = \"/admin/conference/recording\";\n    String Conference_Rtp_Forward = \"/admin/conference/rtp_forward\";\n    String Conference_Stop_Rtp_Forward = \"/admin/conference/stop_rtp_forward\";\n    String Conference_List_Rtp_Forward = \"/admin/conference/list_rtp_forward\";\n\n    String Channel_User_Info = \"/channel/user_info\";\n    String Channel_Update_Profile = \"/channel/update_profile\";\n    String Channel_Get_Profile = \"/channel/get_profile\";\n    String Channel_Message_Send = \"/channel/message/send\";\n    String Channel_Msg_Recall = \"/channel/message/recall\";\n    String Channel_Msg_Republish = \"/channel/message/republish\";\n    String Channel_Subscribe = \"/channel/subscribe\";\n    String Channel_Subscriber_List = \"/channel/subscriber_list\";\n    String Channel_Is_Subscriber = \"/channel/is_subscriber\";\n    String Channel_Application_Get_UserInfo = \"/channel/application/get_user_info\";\n\n    String Robot_User_Info = \"/robot/user_info\";\n    String Robot_Get_Profile = \"/robot/profile\";\n    String Robot_Message_Send = \"/robot/message/send\";\n    String Robot_Message_Reply = \"/robot/message/reply\";\n    String Robot_Message_Recall = \"/robot/message/recall\";\n    String Robot_Message_Update = \"/robot/message/update\";\n    String Robot_Set_Callback = \"/robot/set_callback\";\n    String Robot_Get_Callback = \"/robot/get_callback\";\n    String Robot_Delete_Callback = \"/robot/delete_callback\";\n    String Robot_Update_Profile = \"/robot/update_profile\";\n    String Robot_Application_Get_UserInfo = \"/robot/application/get_user_info\";\n    String Robot_Group_Member_Add = \"/robot/group/member/add\";\n    String Robot_Group_Allow_Member = \"/robot/group/manager/allow\";\n    String Robot_Create_Group = \"/robot/group/create\";\n    String Robot_Group_Dismiss = \"/robot/group/del\";\n    String Robot_Group_Get_Info = \"/robot/group/get_info\";\n    String Robot_Group_Member_List = \"/robot/group/member/list\";\n    String Robot_Group_Member_Get = \"/robot/group/member/get\";\n    String Robot_Group_Member_Kickoff = \"/robot/group/member/del\";\n    String Robot_Group_Modify_Info = \"/robot/group/modify\";\n    String Robot_Group_Set_Member_Alias = \"/robot/group/member/set_alias\";\n    String Robot_Group_Set_Member_Extra = \"/robot/group/member/set_extra\";\n    String Robot_Group_Mute_Member = \"/robot/group/manager/mute\";\n    String Robot_Group_Member_Quit = \"/robot/group/member/quit\";\n    String Robot_Group_Transfer = \"/robot/group/transfer\";\n    String Robot_Group_Set_Manager = \"/robot/group/manager/set\";\n\n    String Robot_Moments_Post_Feed = \"/robot/moments/feed/post\";\n    String Robot_Moments_Pull_Feeds = \"/robot/moments/feed/pull\";\n    String Robot_Moments_Update_Feed = \"/robot/moments/feed/update\";\n    String Robot_Moments_Post_Comment = \"/robot/moments/comment/post\";\n    String Robot_Moments_Pull_Comment = \"/robot/moments/comment/pull\";\n    String Robot_Moments_Fetch_Feed = \"/robot/moments/feed/pull_one\";\n    String Robot_Moments_Fetch_Profiles = \"/robot/moments/profiles/pull\";\n    String Robot_Moments_Recall_Comment = \"/robot/moments/comment/recall\";\n    String Robot_Moments_Recall_Feed = \"/robot/moments/feed/recall\";\n    String Robot_Moments_Update_Profiles_List_Value = \"/robot/moments/profiles/list/push\";\n    String Robot_Moments_Update_Profiles_Value = \"/robot/moments/profiles/value/push\";\n\n    String Robot_Conference_Request = \"/robot/conference/request\";\n\n    String Robot_Get_Presigned_Upload_Url = \"/robot/oss/get_upload_url\";\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/common/ErrorCode.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.common;\n\n/**\n * 错误码枚举\n * <p>\n * 定义了野火IM系统中所有可能的错误码，包括：\n * <ul>\n * <li>通用错误（0-5）</li>\n * <li>认证错误（6-8）</li>\n * <li>消息错误（9-10）</li>\n * <li>群组错误（11-12）</li>\n * <li>用户错误（16-19）</li>\n * <li>聊天室错误（20）</li>\n * <li>频道错误（21-25）</li>\n * <li>会议错误（60-61）</li>\n * <li>应用错误（70）</li>\n * <li>密聊错误（81-87）</li>\n * <li>其他错误（90-255）</li>\n * </ul>\n * </p>\n */\npublic enum ErrorCode {\n    //General error\n    ERROR_CODE_SUCCESS(0, \"success\"),\n    ERROR_CODE_SECRECT_KEY_MISMATCH(1, \"secrect key mismatch\"),\n    ERROR_CODE_INVALID_DATA(2, \"invalid data\"),\n    ERROR_CODE_NODE_NOT_EXIST(3, \"node not exist\"),\n    ERROR_CODE_SERVER_ERROR(4, \"server error\"),\n    ERROR_CODE_NOT_MODIFIED(5, \"not modified\"),\n\n\n    //Auth error\n    ERROR_CODE_TOKEN_ERROR(6, \"token error\"),\n    ERROR_CODE_KICKED_OFF(7, \"kicked off\"),\n    ERROR_CODE_USER_FORBIDDEN(8, \"user forbidden\"),\n\n    //Message error\n    ERROR_CODE_NOT_IN_GROUP(9, \"not in group\"),\n    ERROR_CODE_INVALID_MESSAGE(10, \"invalid message\"),\n\n    //Group error\n    ERROR_CODE_GROUP_ALREADY_EXIST(11, \"group already exist\"),\n    ERROR_CODE_ALREADY_IN_GROUP(12, \"member already in group\"),\n\n    //user error\n    ERROR_CODE_FRIEND_ALREADY_REQUEST(16, \"already send request\"),\n    ERROR_CODE_FRIEND_REQUEST_BLOCKED(18, \"friend request blocked\"),\n    ERROR_CODE_FRIEND_REQUEST_EXPIRED(19, \"friend request expired\"),\n\n    ERROR_CODE_NOT_IN_CHATROOM(20, \"not in chatroom\"),\n\n    ERROR_CODE_NOT_IN_CHANNEL(21, \"not in channel\"),\n\n    ERROR_CODE_NOT_LICENSED(22, \"not licensed\"),\n    ERROR_CODE_ALREADY_FRIENDS(23, \"already friends\"),\n\n    ERROR_CODE_RECALL_TIME_EXPIRED(24, \"time expired\"),\n    ERROR_CODE_LOCK_ALREADY_LOCKED(25, \"already locked\"),\n    ERROR_CODE_NOT_YOUR_LOCKED(26, \"unload failure, not your lock\"),\n    ERROR_CODE_ROBOT_NO_TOKEN(27, \"robot no token\"),\n    ERROR_CODE_WS_NOT_CONFIGURED_CORRECTLY(28, \"ws not configured correctly\"),\n    ERROR_CODE_TIME_INCONSISTENT(30, \"time inconsistent\"),\n    ERROR_CODE_MESSAGE_TOO_LARGE(35, \"message too large\"),\n    ERROR_CODE_CONFERENCE_ROOM_NOT_EXIST(60, \"conference room not exist\"),\n    ERROR_CODE_CONFERENCE_SERVICE_NOT_AVAILABLE(61, \"conference service not available\"),\n\n    ERROR_CODE_APPLICATION_TOKEN_ERROR_OR_TIMEOUT(70, \"application token error or timeout\"),\n\n    ERROR_CODE_SECRET_CHAT_ACCEPTED_BY_OTHER_CLIENT(81, \"secret chat accepted by other client\"),\n    ERROR_CODE_SECRET_CHAT_SESSION_NOT_EXIST(82, \"secret chat session not exist\"),\n    ERROR_CODE_SECRET_CHAT_NOT_SESSION_CLIENT(83, \"not secret chat session client\"),\n    ERROR_CODE_SECRET_CHAT_SESSION_NOT_READY(84, \"secret chat session not ready\"),\n    ERROR_CODE_SECRET_CHAT_SESSION_DESTROYED(85, \"secret chat session destroyed\"),\n    ERROR_CODE_SECRET_CHAT_MO_DISABLED(86, \"origin side disable secret chat\"),\n    ERROR_CODE_SECRET_CHAT_MT_DISABLED(87, \"target side disable secret chat\"),\n\n    ERROR_CODE_CONFERENCE_ERROR(90, \"Conference server response error\"),\n\n    ERROR_CODE_FUNCTION_DISABLED(220, \"function disabled\"),\n    ERROR_CODE_SERVER_BUSY(221, \"Server busy\"),\n    ERROR_CODE_PARTLY_SUCCESS(222, \"Partly success\"),\n\n    ERROR_CODE_OTHER_CLIENT_ALREADY_IN_CHATROOM(225, \"other client already in chatroom\"),\n\n    ERROR_CODE_CHANNEL_NO_EXIST(236, \"channel no exist\"),\n    ERROR_CODE_CHANNEL_NO_SECRET(237, \"channel no secret\"),\n    ERROR_CODE_USER_NOT_PREPARED(238, \"user not prepared\"),\n    ERROR_CODE_API_NOT_SIGNED(239, \"api not signed or sign parameter not completion\"),\n    ERROR_CODE_GROUP_EXCEED_MAX_MEMBER_COUNT(240, \"group exceed max member count\"),\n    ERROR_CODE_GROUP_MUTED(241, \"group is muted\"),\n    ERROR_CODE_SENSITIVE_MATCHED(242, \"sensitive matched\"),\n    ERROR_CODE_SIGN_EXPIRED(243, \"sign expired\"),\n    ERROR_CODE_AUTH_FAILURE(244, \"auth failure\"),\n    ERROR_CODE_USER_BLOCKED(245, \"user is blocked\"),\n    ERROR_CODE_IN_BLACK_LIST(246, \"user in black list\"),\n    ERROR_CODE_FORBIDDEN_SEND_MSG(247, \"forbidden send msg globally\"),\n    ERROR_CODE_NOT_RIGHT(248, \"no right to operate\"),\n    ERROR_CODE_TIMEOUT(249, \"timeout\"),\n    ERROR_CODE_OVER_FREQUENCY(250, \"over frequency\"),\n    INVALID_PARAMETER(251, \"Invalid parameter\"),\n    INVALID_ASYNC_HANDLING(252, \"Async handling\"),\n    ERROR_CODE_NOT_EXIST(253, \"not exist\"),\n    ERROR_CODE_NOT_IMPLEMENT(254, \"not implement\"),\n\n\n    ERROR_CODE_SUCCESS_GZIPED(255, \"success withe gzip response\"),;\n\n    public int code;\n    public String msg;\n\n    ErrorCode(int code, String msg) {\n        this.code = code;\n        this.msg = msg;\n    }\n\n    public static ErrorCode fromCode(int code) {\n        for (ErrorCode errorCode : ErrorCode.values()) {\n            if(errorCode.code == (code&0xff)) {\n                return errorCode;\n            }\n        }\n        return ERROR_CODE_SERVER_ERROR;\n    }\n    public int getCode() {\n        return code;\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/common/IMExceptionEvent.java",
    "content": "package cn.wildfirechat.common;\n\n/**\n * IM异常事件类\n * <p>\n * 用于记录和传递IM系统中的异常事件信息。\n * </p>\n */\npublic class IMExceptionEvent {\n    /**\n     * 事件类型接口\n     * <p>\n     * 定义了各种异常事件的类型常量。\n     * </p>\n     */\n    public interface EventType {\n        int RDBS_Exception = 1;\n        int MONGO_Exception = 2;\n        int RPC_Exception = 3;\n        int PUSH_SERVER_Exception = 4;\n        int ADMIN_API_Exception = 5;\n        int CHANNEL_API_Exception = 6;\n        int ROBOT_API_Exception = 7;\n        int SHORT_LINK_Exception = 8;\n        int EVENT_CALLBACK_Exception = 9;\n        int CONFERENCE_Exception = 10;\n        int HEART_BEAT = 100;\n    }\n\n    public int event_type;\n    public String msg;\n    public String call_stack;\n    public int count;\n    public int node_id;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/ArticleContent.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Base64;\nimport java.util.List;\n\npublic class ArticleContent {\n    public static class Article {\n        public String id;\n        public String cover;\n        public String title;\n        public String digest;\n        public String url;\n        public boolean rr;\n\n        public Article() {\n        }\n\n        public Article(String id, String cover, String title, String digest, String url, boolean rr) {\n            this.id = id;\n            this.cover = cover;\n            this.title = title;\n            this.digest = digest;\n            this.url = url;\n            this.rr = rr;\n        }\n    }\n    public Article top;\n    public List<Article> subArticles;\n\n    public ArticleContent() {\n    }\n\n    public ArticleContent(String id, String cover, String title, String digest, String url, boolean rr) {\n        this.top = new Article(id, cover, title, digest, url, rr);\n    }\n\n    public ArticleContent addSubArticle(String id, String cover, String title, String digest, String url, boolean rr)  {\n        if (subArticles == null)\n            subArticles = new ArrayList<>();\n        subArticles.add(new Article(id, cover, title, digest, url, rr));\n        return this;\n    }\n\n    public MessagePayload toPayload() {\n        MessagePayload payload = new MessagePayload();\n        payload.setType(13);\n        payload.setSearchableContent(top.title);\n        payload.setBase64edData(Base64.getEncoder().encodeToString(new GsonBuilder().disableHtmlEscaping().create().toJson(this).getBytes(StandardCharsets.UTF_8)));\n        return payload;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/BroadMessageData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\npublic class BroadMessageData {\n    private String sender;\n    private int line;\n    private MessagePayload payload;\n\n    public String getSender() {\n        return sender;\n    }\n\n    public void setSender(String sender) {\n        this.sender = sender;\n    }\n\n    public int getLine() {\n        return line;\n    }\n\n    public void setLine(int line) {\n        this.line = line;\n    }\n\n    public MessagePayload getPayload() {\n        return payload;\n    }\n\n    public void setPayload(MessagePayload payload) {\n        this.payload = payload;\n    }\n\n    public static boolean isValide(BroadMessageData sendMessageData) {\n        if(sendMessageData == null ||\n            StringUtil.isNullOrEmpty(sendMessageData.getSender()) ||\n            sendMessageData.getPayload() == null) {\n            return false;\n        }\n        return true;\n    }\n\n    public WFCMessage.Message toProtoMessage() {\n        return WFCMessage.Message.newBuilder().setFromUser(sender)\n            .setConversation(WFCMessage.Conversation.newBuilder().setType(ProtoConstants.ConversationType.ConversationType_Private).setTarget(sender).setLine(line))\n            .setContent(payload.toProtoMessageContent())\n            .build();\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/BroadMessageResult.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class BroadMessageResult {\n    private long messageUid;\n    private long count;\n\n    public BroadMessageResult() {\n    }\n\n    public BroadMessageResult(long messageUid, long count) {\n        this.messageUid = messageUid;\n        this.count = count;\n    }\n\n    public long getMessageUid() {\n        return messageUid;\n    }\n\n    public void setMessageUid(long messageUid) {\n        this.messageUid = messageUid;\n    }\n\n    public long getCount() {\n        return count;\n    }\n\n    public void setCount(long count) {\n        this.count = count;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/ChannelUpdateEvent.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class ChannelUpdateEvent {\n    public String operatorId;\n    public String channelId;\n    public int type;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/ChatroomMemberUpdateEvent.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class ChatroomMemberUpdateEvent {\n    public String operatorId;\n    public String chatroomId;\n    public List<String> memberIds;\n    public int type;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/ChatroomUpdateEvent.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class ChatroomUpdateEvent {\n    public String chatroomId;\n    public int type;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/ConferenceCreateEvent.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class ConferenceCreateEvent {\n    public String userId;\n    public String roomId;\n    public String serverId;\n    public String description;\n    public String pin;\n    public int max_publishers;\n    public int bitrate;\n    public boolean advance;\n    public boolean recording;\n    public long timestamp;\n\n    public ConferenceCreateEvent() {\n        timestamp = System.currentTimeMillis();\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/ConferenceDestroyEvent.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class ConferenceDestroyEvent {\n    public String userId;\n    public String roomId;\n    public long timestamp;\n\n    public ConferenceDestroyEvent() {\n        timestamp = System.currentTimeMillis();\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/ConferenceJoinEvent.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class ConferenceJoinEvent {\n    public String userId;\n    public String roomId;\n    public boolean screenSharing;\n    public long timestamp;\n\n    public ConferenceJoinEvent() {\n        timestamp = System.currentTimeMillis();\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/ConferenceLeaveEvent.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class ConferenceLeaveEvent {\n    public String userId;\n    public String roomId;\n    public boolean rejoin;\n    public boolean kicked;\n    public boolean screenSharing;\n    public long timestamp;\n\n    public ConferenceLeaveEvent() {\n        timestamp = System.currentTimeMillis();\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/ConferencePublishEvent.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class ConferencePublishEvent {\n    public String userId;\n    public boolean video;\n    public String roomId;\n    public boolean screenSharing;\n    public long timestamp;\n\n    public ConferencePublishEvent() {\n        timestamp = System.currentTimeMillis();\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/ConferenceUnpublishEvent.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class ConferenceUnpublishEvent {\n    public String userId;\n    public String roomId;\n    public boolean screenSharing;\n    public long timestamp;\n\n    public ConferenceUnpublishEvent() {\n        timestamp = System.currentTimeMillis();\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/Conversation.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n/**\n * 会话类\n * <p>\n * 表示一个会话对象，包含会话类型、目标ID和线路信息。\n * 用于标识消息发送或接收的目标会话。\n * </p>\n */\npublic class Conversation {\n    private int type;\n    private String target;\n    private int line;\n\n    public Conversation() {\n    }\n\n    public Conversation(int type, String target, int line) {\n        this.type = type;\n        this.target = target;\n        this.line = line;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public String getTarget() {\n        return target;\n    }\n\n    public void setTarget(String target) {\n        this.target = target;\n    }\n\n    public int getLine() {\n        return line;\n    }\n\n    public void setLine(int line) {\n        this.line = line;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/DeleteMessageData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class DeleteMessageData {\n    private long messageUid;\n\n    public long getMessageUid() {\n        return messageUid;\n    }\n\n    public void setMessageUid(long messageUid) {\n        this.messageUid = messageUid;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/FilesPojo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class FilesPojo {\n    public int total;\n    public List<FilePojo> files;\n    public static class FilePojo {\n        public long messageId;\n        public String sender;\n        public int conversationType;\n        public String target;\n        public int line;\n        public String name;\n        public String url;\n        public int size;\n        public int downloadCount;\n        public long timestamp;\n    }\n}\n\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/ForwardDeviceMessageData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class ForwardDeviceMessageData {\n    private String deviceId;\n    private int type;\n    private byte[] data;\n\n    public ForwardDeviceMessageData() {\n    }\n\n    public ForwardDeviceMessageData(String deviceId, int type, byte[] data) {\n        this.deviceId = deviceId;\n        this.type = type;\n        this.data = data;\n    }\n\n    public String getDeviceId() {\n        return deviceId;\n    }\n\n    public void setDeviceId(String deviceId) {\n        this.deviceId = deviceId;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public byte[] getData() {\n        return data;\n    }\n\n    public void setData(byte[] data) {\n        this.data = data;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/GetConversationFilesPojo.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class GetConversationFilesPojo {\n    public int conversationType;\n    public String target;\n    public int line;\n    public String userId;\n    public int offset;\n    public boolean desc;\n    public int count;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/GetOnlineUserCountResult.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.ArrayList;\n\npublic class GetOnlineUserCountResult extends ArrayList<GetOnlineUserCountResult.Node> {\n    public static class Node {\n        public int node;\n        public int count;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/GetOnlineUserRequest.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.ArrayList;\n\npublic class GetOnlineUserRequest {\n    public int nodeId;\n    public int offset;\n    public int count;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/GetOnlineUserResult.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.ArrayList;\n\npublic class GetOnlineUserResult {\n    public static class UserClient {\n        public String userId;\n        public String clientId;\n        public int platform;\n        public String ip;\n    }\n\n    public ArrayList<GetOnlineUserResult.UserClient> userClients;\n    public int totalCount;\n    public int offset;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/GetUserFilesPojo.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class GetUserFilesPojo {\n    public String userId;\n    public int offset;\n    public boolean desc;\n    public int count;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/GetUserSessionResult.java",
    "content": "package cn.wildfirechat.pojos;\n\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class GetUserSessionResult {\n    public static class UserSession {\n        public String userId;\n        public String clientId;\n        public int platform;\n        public int pushType;\n        public String deviceToken;\n        public String deviceVoipToken;\n        boolean isOnline;\n\n        public UserSession() {\n        }\n\n        public UserSession(String userId, String clientId, int platform, int pushType, String deviceToken, String deviceVoipToken, boolean isOnline) {\n            this.userId = userId;\n            this.clientId = clientId;\n            this.platform = platform;\n            this.pushType = pushType;\n            this.deviceToken = deviceToken;\n            this.deviceVoipToken = deviceVoipToken;\n            this.isOnline = isOnline;\n        }\n    }\n\n    public List<UserSession> userSessions;\n\n    public GetUserSessionResult() {\n        userSessions = new ArrayList<>();\n    }\n}\n\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/GroupMemberUpdateEvent.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class GroupMemberUpdateEvent {\n    public String operatorId;\n    public String groupId;\n    public List<String> memberIds;\n    public int type;\n    public String value;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/GroupNotificationBinaryContent.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.protobuf.ByteString;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic class GroupNotificationBinaryContent {\n    //groupId\n    private String g;\n\n    //operator\n    private String o;\n\n    //value1(name or something)\n    private String n;\n\n    //members\n    private List<String> ms;\n\n    //value2(member or something)\n    private String m;\n\n    private Map<String, Integer> mi;\n\n    private String extra;\n\n    public GroupNotificationBinaryContent() {\n    }\n\n    public GroupNotificationBinaryContent(String g, String o, String n, String m) {\n        this.g = g;\n        this.o = o;\n        this.n = n;\n        this.m = m;\n    }\n\n    public GroupNotificationBinaryContent(String g, String operator, String name, List<String> members) {\n        this.g = g;\n        this.o = operator;\n        this.n = name;\n        this.ms = members;\n    }\n\n    public String getG() {\n        return g;\n    }\n\n    public void setG(String g) {\n        this.g = g;\n    }\n\n    public String getM() {\n        return m;\n    }\n\n    public void setM(String m) {\n        this.m = m;\n    }\n\n    public String getO() {\n        return o;\n    }\n\n    public void setO(String o) {\n        this.o = o;\n    }\n\n    public String getN() {\n        return n;\n    }\n\n    public void setN(String n) {\n        this.n = n;\n    }\n\n    public List<String> getMs() {\n        return ms;\n    }\n\n    public void setMs(List<String> ms) {\n        this.ms = ms;\n    }\n\n    public GroupNotificationBinaryContent setMi(Map<String, Integer> mi) {\n        this.mi = mi;\n        return this;\n    }\n\n    public GroupNotificationBinaryContent setExtra(String extra) {\n        this.extra = extra;\n        return this;\n    }\n\n    public WFCMessage.MessageContent getGroupNotifyContent(int groupContentType) {\n        WFCMessage.MessageContent.Builder builder = WFCMessage.MessageContent.newBuilder().setType(groupContentType).setData(ByteString.copyFromUtf8(new GsonBuilder().disableHtmlEscaping().create().toJson(this)));\n        if(!StringUtil.isNullOrEmpty(extra)) {\n            builder.setExtra(extra);\n        }\n        return builder.build();\n\n    }\n\n    public WFCMessage.MessageContent getAddGroupNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_ADD_GROUP_MEMBER);\n    }\n\n    public WFCMessage.MessageContent getCreateGroupNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_CREATE_GROUP);\n    }\n\n    public WFCMessage.MessageContent getDismissGroupNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_DISMISS_GROUP);\n    }\n\n    public WFCMessage.MessageContent getKickokfMemberGroupNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_KICKOF_GROUP_MEMBER);\n    }\n\n    public WFCMessage.MessageContent getKickokfMemberVisibleGroupNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_KICKOF_GROUP_MEMBER_VISIBLE);\n    }\n\n    public WFCMessage.MessageContent getQuitGroupNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_QUIT_GROUP);\n    }\n\n    public WFCMessage.MessageContent getQuitVisibleGroupNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_QUIT_GROUP_VISIBLE);\n    }\n\n    public WFCMessage.MessageContent getTransferGroupNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_TRANSFER_GROUP_OWNER);\n    }\n\n    public WFCMessage.MessageContent getChangeGroupNameNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_CHANGE_GROUP_NAME);\n    }\n\n    public WFCMessage.MessageContent getChangeGroupPortraitNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_CHANGE_GROUP_PORTRAIT);\n    }\n\n    public WFCMessage.MessageContent getModifyGroupMemberAliasNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_MODIFY_GROUP_ALIAS);\n    }\n\n    public WFCMessage.MessageContent getModifyGroupMemberExtraNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_MODIFY_GROUP_MEMBER_EXTRA);\n    }\n\n    public WFCMessage.MessageContent getChangeGroupMuteNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_CHANGE_MUTE);\n    }\n\n    public WFCMessage.MessageContent getChangeGroupJointypeNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_CHANGE_JOINTYPE);\n    }\n\n    public WFCMessage.MessageContent getChangeGroupPrivatechatNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_CHANGE_PRIVATECHAT);\n    }\n\n    public WFCMessage.MessageContent getChangeGroupSearchableNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_CHANGE_SEARCHABLE);\n    }\n\n    public WFCMessage.MessageContent getSetGroupManagerNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_SET_MANAGER);\n    }\n\n    public WFCMessage.MessageContent getMuteGroupMemberNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_MUTE_MEMBER);\n    }\n\n    public WFCMessage.MessageContent getAllowGroupMemberNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_ALLOW_MEMBER);\n    }\n\n    public WFCMessage.MessageContent getChangeGroupExtraNotifyContent() {\n        return getGroupNotifyContent(ProtoConstants.MESSAGE_CONTENT_TYPE_MODIFY_GROUP_EXTRA);\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/GroupUpdateEvent.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class GroupUpdateEvent {\n    public String operatorId;\n    public String groupId;\n    public int type;\n    public PojoGroupInfo groupInfo;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/HealthCheckResult.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class HealthCheckResult extends ArrayList<HealthCheckResult.Node>\n{\n    public static class Node {\n        public String node;\n        public CPU cpu;\n        public Memory memory;\n        public Disk disk;\n    }\n\n    public static class Memory {\n        public long avail;\n        public long max;\n        public long free;\n    }\n    public static class Disk {\n        public long usable;\n        public long free;\n        public long space;\n    }\n    public static class CPU {\n        public int cores;\n        public double load;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputAddFriendRequest.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputAddFriendRequest {\n    private String userId;\n    private String friendUid;\n    private String reason;\n    private boolean force;\n\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getFriendUid() {\n        return friendUid;\n    }\n\n    public void setFriendUid(String friendUid) {\n        this.friendUid = friendUid;\n    }\n\n    public String getReason() {\n        return reason;\n    }\n\n    public void setReason(String reason) {\n        this.reason = reason;\n    }\n\n    public boolean isForce() {\n        return force;\n    }\n\n    public void setForce(boolean force) {\n        this.force = force;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputAddGroupMember.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\n/**\n * 添加群组成员输入参数类\n * <p>\n * 封装添加群组成员的输入参数，包括群组ID、成员列表、成员额外信息等。\n * </p>\n */\npublic class InputAddGroupMember extends InputGroupBase {\n    private String group_id;\n    private List<PojoGroupMember> members;\n    private String member_extra;\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public List<PojoGroupMember> getMembers() {\n        return members;\n    }\n\n    public void setMembers(List<PojoGroupMember> members) {\n        this.members = members;\n    }\n\n    public String getMember_extra() {\n        return member_extra;\n    }\n\n    public void setMemberExtra(String extra) {\n        this.member_extra = extra;\n    }\n\n    public boolean isValide() {\n        return true;\n    }\n\n    public WFCMessage.AddGroupMemberRequest toProtoGroupRequest() {\n        WFCMessage.AddGroupMemberRequest.Builder addGroupBuilder = WFCMessage.AddGroupMemberRequest.newBuilder();\n        addGroupBuilder.setGroupId(group_id);\n        if(!StringUtil.isNullOrEmpty(member_extra)) {\n            addGroupBuilder.setExtra(member_extra);\n        }\n        for (PojoGroupMember pojoGroupMember : getMembers()) {\n            WFCMessage.GroupMember.Builder groupMemberBuilder = WFCMessage.GroupMember.newBuilder().setMemberId(pojoGroupMember.getMember_id());\n            if (!StringUtil.isNullOrEmpty(pojoGroupMember.getAlias())) {\n                groupMemberBuilder.setAlias(pojoGroupMember.getAlias());\n            }\n            groupMemberBuilder.setType(pojoGroupMember.getType());\n            if(!StringUtil.isNullOrEmpty(pojoGroupMember.getExtra())) {\n                groupMemberBuilder.setExtra(pojoGroupMember.getExtra());\n            }\n            addGroupBuilder.addAddedMember(groupMemberBuilder);\n        }\n\n        if (to_lines != null) {\n            for (Integer line : to_lines\n            ) {\n                addGroupBuilder.addToLine(line);\n            }\n        }\n\n        if (notify_message != null) {\n            addGroupBuilder.setNotifyContent(notify_message.toProtoMessageContent());\n        }\n        return addGroupBuilder.build();\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputApplicationGetUserInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputApplicationGetUserInfo {\n    private String authCode;\n\n    public String getAuthCode() {\n        return authCode;\n    }\n\n    public void setAuthCode(String authCode) {\n        this.authCode = authCode;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputBlacklistRequest.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputBlacklistRequest {\n    private String userId;\n    private String targetUid;\n    private int status;\n\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getTargetUid() {\n        return targetUid;\n    }\n\n    public void setTargetUid(String targetUid) {\n        this.targetUid = targetUid;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputChannelId.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class InputChannelId {\n    public String channelId;\n\n    public InputChannelId() {\n    }\n\n    public InputChannelId(String channelId) {\n        this.channelId = channelId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputChannelSubscribe.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputChannelSubscribe {\n    private String target;\n    private int subscribe; //1，订阅；0，取消订阅\n\n    public String getTarget() {\n        return target;\n    }\n\n    public void setTarget(String target) {\n        this.target = target;\n    }\n\n    public int getSubscribe() {\n        return subscribe;\n    }\n\n    public void setSubscribe(int subscribe) {\n        this.subscribe = subscribe;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputChatroomId.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class InputChatroomId {\n    public String chatroomId;\n\n    public InputChatroomId() {\n    }\n\n    public InputChatroomId(String chatroomId) {\n        this.chatroomId = chatroomId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputChatroomMute.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputChatroomMute {\n    private String chatroomId;\n    private int status;\n\n    public InputChatroomMute() {\n    }\n\n    public InputChatroomMute(String chatroomId, int status) {\n        this.chatroomId = chatroomId;\n        this.status = status;\n    }\n\n    public String getChatroomId() {\n        return chatroomId;\n    }\n\n    public void setChatroomId(String chatroomId) {\n        this.chatroomId = chatroomId;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputClearUserMessages.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputClearUserMessages {\n    public InputClearUserMessages() {\n    }\n\n    public InputClearUserMessages(String userId, Conversation conversation, long startTime, long endTime) {\n        this.userId = userId;\n        this.conversation = conversation;\n        this.startTime = startTime;\n        this.endTime = endTime;\n    }\n\n    public String userId;\n    public Conversation conversation;\n    public long startTime;\n    public long endTime;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputConferenceRequest.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information; please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputConferenceRequest {\n    public String userId;\n    public String clientId;\n    public String request;\n    public long sessionId;\n    public String roomId;\n    public String data;\n    public boolean advance;\n\n    public InputConferenceRequest() {\n    }\n\n    public InputConferenceRequest(String userId, String clientId, String request, long sessionId, String roomId, String data, boolean advance) {\n        this.userId = userId;\n        this.clientId = clientId;\n        this.request = request;\n        this.sessionId = sessionId;\n        this.roomId = roomId;\n        this.data = data;\n        this.advance = advance;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputCountOffset.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class InputCountOffset {\n    public int count;\n    public int offset;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputCreateChannel.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class InputCreateChannel {\n    private String owner;\n    private String name;\n    private String targetId;\n    private String callback;\n    private String portrait;\n    private int auto;\n    private String secret;\n    private String desc;\n    private int state;\n    private String extra;\n    private long updateDt;\n    public List<PojoChannelMenu> menus;\n\n    public WFCMessage.ChannelInfo toProtoChannelInfo() {\n        WFCMessage.ChannelInfo.Builder builder = WFCMessage.ChannelInfo.newBuilder().setOwner(owner);\n        if (!StringUtil.isNullOrEmpty(name))\n            builder = builder.setName(name);\n        if (!StringUtil.isNullOrEmpty(targetId))\n            builder = builder.setTargetId(targetId);\n        if (!StringUtil.isNullOrEmpty(callback))\n            builder = builder.setCallback(callback);\n        if (!StringUtil.isNullOrEmpty(portrait))\n            builder = builder.setPortrait(portrait);\n        builder = builder.setAutomatic(auto);\n        if (!StringUtil.isNullOrEmpty(secret))\n            builder = builder.setSecret(secret);\n        if (!StringUtil.isNullOrEmpty(desc))\n            builder = builder.setDesc(desc);\n        builder = builder.setStatus(state);\n        if (!StringUtil.isNullOrEmpty(extra))\n            builder = builder.setExtra(extra);\n        if (!StringUtil.isNullOrEmpty(name))\n            builder = builder.setUpdateDt(updateDt);\n        else\n            builder = builder.setUpdateDt(System.currentTimeMillis());\n\n        if (menus != null && !menus.isEmpty()) {\n            for (PojoChannelMenu menu : menus) {\n                builder.addMenu(menu.toPbInfo());\n            }\n        }\n\n        return builder.build();\n    }\n\n    public String getOwner() {\n        return owner;\n    }\n\n    public void setOwner(String owner) {\n        this.owner = owner;\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 String getTargetId() {\n        return targetId;\n    }\n\n    public void setTargetId(String targetId) {\n        this.targetId = targetId;\n    }\n\n    public String getCallback() {\n        return callback;\n    }\n\n    public void setCallback(String callback) {\n        this.callback = callback;\n    }\n\n    public String getPortrait() {\n        return portrait;\n    }\n\n    public void setPortrait(String portrait) {\n        this.portrait = portrait;\n    }\n\n    public int getAuto() {\n        return auto;\n    }\n\n    public void setAuto(int auto) {\n        this.auto = auto;\n    }\n\n    public String getSecret() {\n        return secret;\n    }\n\n    public void setSecret(String secret) {\n        this.secret = secret;\n    }\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    public int getState() {\n        return state;\n    }\n\n    public void setState(int state) {\n        this.state = state;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public long getUpdateDt() {\n        return updateDt;\n    }\n\n    public void setUpdateDt(long updateDt) {\n        this.updateDt = updateDt;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputCreateChatroom.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\npublic class InputCreateChatroom {\n    private String chatroomId;\n    private String title;\n    private String desc;\n    private String portrait;\n    private String extra;\n    private Integer state;\n\n    public WFCMessage.ChatroomInfo toChatroomInfo() {\n        WFCMessage.ChatroomInfo.Builder builder = WFCMessage.ChatroomInfo.newBuilder().setTitle(title);\n        if (!StringUtil.isNullOrEmpty(desc)) {\n            builder.setDesc(desc);\n        }\n\n        if (!StringUtil.isNullOrEmpty(portrait)) {\n            builder.setPortrait(portrait);\n        }\n\n        long current = System.currentTimeMillis();\n        builder.setCreateDt(current).setUpdateDt(current).setMemberCount(0);\n\n        if (!StringUtil.isNullOrEmpty(extra)) {\n            builder.setExtra(extra);\n        }\n\n        if (state == null || state == 0) {\n            builder.setState(ProtoConstants.ChatroomState.Chatroom_State_Normal);\n        } else if(state == 1) {\n            builder.setState(ProtoConstants.ChatroomState.Chatroom_State_NotStart);\n        } else {\n            builder.setState(ProtoConstants.ChatroomState.Chatroom_State_End);\n        }\n\n        return builder.build();\n    }\n    public InputCreateChatroom() {\n    }\n\n    public Integer getState() {\n        return state;\n    }\n\n    public void setState(Integer state) {\n        this.state = state;\n    }\n\n    public String getChatroomId() {\n        return chatroomId;\n    }\n\n    public void setChatroomId(String chatroomId) {\n        this.chatroomId = chatroomId;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    public String getPortrait() {\n        return portrait;\n    }\n\n    public void setPortrait(String portrait) {\n        this.portrait = portrait;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputCreateDevice.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class InputCreateDevice {\n    private String deviceId;\n    private List<String> owners;\n    private String extra;\n\n    public List<String> getOwners() {\n        return owners;\n    }\n\n    public void setOwners(List<String> owners) {\n        this.owners = owners;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public String getDeviceId() {\n        return deviceId;\n    }\n\n    public void setDeviceId(String deviceId) {\n        this.deviceId = deviceId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputCreateGroup.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\n/**\n * 创建群组输入参数类\n * <p>\n * 封装创建群组的输入参数，包括群组信息、成员列表、成员额外信息等。\n * </p>\n */\npublic class InputCreateGroup extends InputGroupBase {\n    private PojoGroup group;\n    private String member_extra;\n\n    public boolean isValide() {\n        return !StringUtil.isNullOrEmpty(operator) && group != null;\n    }\n\n    public WFCMessage.CreateGroupRequest toProtoGroupRequest() {\n        WFCMessage.Group.Builder groupBuilder = WFCMessage.Group.newBuilder();\n        WFCMessage.GroupInfo.Builder groupInfoBuilder = WFCMessage.GroupInfo.newBuilder();\n        PojoGroupInfo group_info = group.getGroup_info();\n        if (!StringUtil.isNullOrEmpty(group_info.target_id)) {\n            groupInfoBuilder.setTargetId(group_info.getTarget_id());\n        }\n\n        if (!StringUtil.isNullOrEmpty(group_info.name)) {\n            groupInfoBuilder.setName(group_info.getName());\n        }\n\n        if (!StringUtil.isNullOrEmpty(group_info.portrait)) {\n            groupInfoBuilder.setPortrait(group_info.getPortrait());\n        }\n        if (!StringUtil.isNullOrEmpty(group_info.owner)) {\n            groupInfoBuilder.setOwner(group_info.getOwner());\n        }\n\n        groupInfoBuilder.setType(group_info.getType());\n\n        if (!StringUtil.isNullOrEmpty(group_info.extra)) {\n            groupInfoBuilder.setExtra(group_info.getExtra());\n        }\n\n        if (group_info.join_type > 0 && group_info.join_type < 128) {\n            groupInfoBuilder.setJoinType(group_info.join_type);\n        }\n\n        if (group_info.mute > 0 && group_info.mute < 128) {\n            groupInfoBuilder.setMute(group_info.mute);\n        }\n        if (group_info.private_chat > 0 && group_info.private_chat < 128) {\n            groupInfoBuilder.setPrivateChat(group_info.private_chat);\n        }\n        if (group_info.searchable > 0 && group_info.searchable < 128) {\n            groupInfoBuilder.setSearchable(group_info.searchable);\n        }\n        if(group_info.history_message > 0&& group_info.history_message < 128) {\n            groupInfoBuilder.setHistoryMessage(group_info.history_message);\n        }\n        if(group_info.max_member_count > 0) {\n            groupInfoBuilder.setMaxMemberCount(group_info.max_member_count);\n        }\n        if(group_info.isSuper_group()) {\n            groupInfoBuilder.setSuperGroup(1);\n        }\n        groupInfoBuilder.setDeleted(0);\n\n        groupBuilder.setGroupInfo(groupInfoBuilder);\n        if(group.getMembers() != null) {\n            for (PojoGroupMember pojoGroupMember : group.getMembers()) {\n                WFCMessage.GroupMember.Builder groupMemberBuilder = WFCMessage.GroupMember.newBuilder().setMemberId(pojoGroupMember.getMember_id());\n                if (!StringUtil.isNullOrEmpty(pojoGroupMember.getAlias())) {\n                    groupMemberBuilder.setAlias(pojoGroupMember.getAlias());\n                }\n                groupMemberBuilder.setType(pojoGroupMember.getType());\n                if (!StringUtil.isNullOrEmpty(pojoGroupMember.getExtra())) {\n                    groupMemberBuilder.setExtra(pojoGroupMember.extra);\n                }\n                groupBuilder.addMembers(groupMemberBuilder);\n            }\n        }\n\n        WFCMessage.CreateGroupRequest.Builder createGroupReqBuilder = WFCMessage.CreateGroupRequest.newBuilder();\n        createGroupReqBuilder.setGroup(groupBuilder);\n        if(!StringUtil.isNullOrEmpty(member_extra)) {\n            createGroupReqBuilder.setMemberExtra(member_extra);\n        }\n        if (to_lines != null) {\n            for (Integer line : to_lines\n            ) {\n                createGroupReqBuilder.addToLine(line);\n            }\n        }\n\n        if (notify_message != null) {\n            createGroupReqBuilder.setNotifyContent(notify_message.toProtoMessageContent());\n        }\n        return createGroupReqBuilder.build();\n    }\n\n    public PojoGroup getGroup() {\n        return group;\n    }\n\n    public void setGroup(PojoGroup group) {\n        this.group = group;\n    }\n\n    public String getMember_extra() {\n        return member_extra;\n    }\n\n    public void setMember_extra(String member_extra) {\n        this.member_extra = member_extra;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputCreateRobot.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\npublic class InputCreateRobot {\n    private String userId;\n    private String name;\n    private String password;\n    private String displayName;\n    private String portrait;\n    private int gender;\n    private String mobile;\n    private String email;\n    private String address;\n    private String company;\n    private String social;\n    private String extra;\n    private long updateDt;\n\n\n    private String owner;\n    private String secret;\n    private String callback;\n    private String robotExtra;\n\n    public String getSocial() {\n        return social;\n    }\n\n    public void setSocial(String social) {\n        this.social = social;\n    }\n\n    public WFCMessage.Robot toRobot() {\n        WFCMessage.Robot.Builder builder = WFCMessage.Robot.newBuilder();\n        if (!StringUtil.isNullOrEmpty(userId))\n            builder.setUid(userId);\n        if (!StringUtil.isNullOrEmpty(owner))\n        builder.setOwner(owner);\n        if (!StringUtil.isNullOrEmpty(secret))\n        builder.setSecret(secret);\n        if (!StringUtil.isNullOrEmpty(callback))\n        builder.setCallback(callback);\n        if (!StringUtil.isNullOrEmpty(robotExtra))\n        builder.setExtra(robotExtra);\n        builder.setState(0);\n        return builder.build();\n    }\n\n    public WFCMessage.User toUser() {\n        WFCMessage.User.Builder newUserBuilder = WFCMessage.User.newBuilder()\n            .setUid(userId);\n        if (name != null)\n            newUserBuilder.setName(name);\n        if (displayName != null)\n            newUserBuilder.setDisplayName(displayName);\n        if (getPortrait() != null)\n            newUserBuilder.setPortrait(getPortrait());\n        if (getEmail() != null)\n            newUserBuilder.setEmail(getEmail());\n        if (getAddress() != null)\n            newUserBuilder.setAddress(getAddress());\n        if (getCompany() != null)\n            newUserBuilder.setCompany(getCompany());\n        if (getSocial() != null)\n            newUserBuilder.setSocial(getSocial());\n\n        if (getMobile() != null)\n            newUserBuilder.setMobile(getMobile());\n        if (getExtra() != null)\n            newUserBuilder.setExtra(getExtra());\n        newUserBuilder.setType(ProtoConstants.UserType.UserType_Robot);\n        newUserBuilder.setGender(gender);\n\n        newUserBuilder.setUpdateDt(System.currentTimeMillis());\n        return newUserBuilder.build();\n    }\n\n    public long getUpdateDt() {\n        return updateDt;\n    }\n\n    public void setUpdateDt(long updateDt) {\n        this.updateDt = updateDt;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\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 String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    public void setDisplayName(String displayName) {\n        this.displayName = displayName;\n    }\n\n    public String getPortrait() {\n        return portrait;\n    }\n\n    public void setPortrait(String portrait) {\n        this.portrait = portrait;\n    }\n\n    public String getMobile() {\n        return mobile;\n    }\n\n    public void setMobile(String mobile) {\n        this.mobile = mobile;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    public String getCompany() {\n        return company;\n    }\n\n    public void setCompany(String company) {\n        this.company = company;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public int getGender() {\n        return gender;\n    }\n\n    public void setGender(int gender) {\n        this.gender = gender;\n    }\n\n    public String getOwner() {\n        return owner;\n    }\n\n    public void setOwner(String owner) {\n        this.owner = owner;\n    }\n\n    public String getSecret() {\n        return secret;\n    }\n\n    public void setSecret(String secret) {\n        this.secret = secret;\n    }\n\n    public String getCallback() {\n        return callback;\n    }\n\n    public void setCallback(String callback) {\n        this.callback = callback;\n    }\n\n    public String getRobotExtra() {\n        return robotExtra;\n    }\n\n    public void setRobotExtra(String robotExtra) {\n        this.robotExtra = robotExtra;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputDestoryChatroom.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputDestoryChatroom {\n    private String chatroomId;\n\n    public InputDestoryChatroom() {\n    }\n\n    public String getChatroomId() {\n        return chatroomId;\n    }\n\n    public void setChatroomId(String chatroomId) {\n        this.chatroomId = chatroomId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputDestroyUser.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputDestroyUser {\n    private String userId;\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputDeviceId.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputDeviceId {\n    private String deviceId;\n\n    public String getDeviceId() {\n        return deviceId;\n    }\n\n    public void setDeviceId(String deviceId) {\n        this.deviceId = deviceId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputDismissGroup.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class InputDismissGroup extends InputGroupBase {\n    private String group_id;\n\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public boolean isValide() {\n        if (StringUtil.isNullOrEmpty(group_id) || StringUtil.isNullOrEmpty(operator))\n            return false;\n        return true;\n    }\n\n    public WFCMessage.DismissGroupRequest toProtoGroupRequest() {\n        WFCMessage.DismissGroupRequest.Builder dismissGroupBuilder = WFCMessage.DismissGroupRequest.newBuilder();\n        dismissGroupBuilder.setGroupId(group_id);\n\n        if (to_lines != null) {\n            for (Integer line : to_lines\n            ) {\n                dismissGroupBuilder.addToLine(line);\n            }\n        }\n\n        if (notify_message != null) {\n            dismissGroupBuilder.setNotifyContent(notify_message.toProtoMessageContent());\n        }\n        return dismissGroupBuilder.build();\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetAlias.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputGetAlias {\n    private String operator;\n    private String targetId;\n\n    public String getTargetId() {\n        return targetId;\n    }\n\n    public void setTargetId(String targetId) {\n        this.targetId = targetId;\n    }\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetChannelInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputGetChannelInfo {\n    private String channelId;\n\n    public InputGetChannelInfo(String channelId) {\n        this.channelId = channelId;\n    }\n\n    public String getChannelId() {\n        return channelId;\n    }\n\n    public void setChannelId(String channelId) {\n        this.channelId = channelId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetChatroomInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputGetChatroomInfo {\n    private String chatroomId;\n\n    public InputGetChatroomInfo(String chatroomId) {\n        this.chatroomId = chatroomId;\n    }\n\n    public String getChatroomId() {\n        return chatroomId;\n    }\n\n    public void setChatroomId(String chatroomId) {\n        this.chatroomId = chatroomId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetConvReadTime.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputGetConvReadTime {\n    private String userId;\n    private int conversationType;\n    private String target;\n    private int line;\n\n    public InputGetConvReadTime() {\n    }\n\n    public InputGetConvReadTime(String userId, int conversationType, String target, int line) {\n        this.userId = userId;\n        this.conversationType = conversationType;\n        this.target = target;\n        this.line = line;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public int getConversationType() {\n        return conversationType;\n    }\n\n    public void setConversationType(int conversationType) {\n        this.conversationType = conversationType;\n    }\n\n    public String getTarget() {\n        return target;\n    }\n\n    public void setTarget(String target) {\n        this.target = target;\n    }\n\n    public int getLine() {\n        return line;\n    }\n\n    public void setLine(int line) {\n        this.line = line;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetFriendList.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\npublic class InputGetFriendList {\n    private String userId;\n    private int status;\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetGroup.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputGetGroup {\n    private String groupId;\n\n    public String getGroupId() {\n        return groupId;\n    }\n\n    public void setGroupId(String groupId) {\n        this.groupId = groupId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetGroupMember.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputGetGroupMember {\n    private String groupId;\n    private String memberId;\n\n    public String getGroupId() {\n        return groupId;\n    }\n\n    public void setGroupId(String groupId) {\n        this.groupId = groupId;\n    }\n\n    public String getMemberId() {\n        return memberId;\n    }\n\n    public void setMemberId(String memberId) {\n        this.memberId = memberId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetPresignedUploadUrl.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\n/**\n * 请求预签名上传地址\n * <p>\n * 请求封装预签名上传地址，包括：\n * <ul>\n * <li>文件名</li>\n * <li>文件类型</li>\n * <li>媒体类型</li>\n * </ul>\n * </p>\n */\npublic class InputGetPresignedUploadUrl {\n    public String fileName;\n    public String contentType;\n    public int mediaType;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetToken.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class InputGetToken {\n    private String userId;\n    private String clientId;\n    private Integer platform;\n\n    public InputGetToken() {\n    }\n\n    public InputGetToken(String userId, String clientId, int platform) {\n        this.userId = userId;\n        this.clientId = clientId;\n        this.platform = platform;\n    }\n\n    public Integer getPlatform() {\n        return platform;\n    }\n\n    public void setPlatform(Integer platform) {\n        this.platform = platform;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getClientId() {\n        return clientId;\n    }\n\n    public void setClientId(String clientId) {\n        this.clientId = clientId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetUserGroupByType.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class InputGetUserGroupByType {\n    private String userId;\n    private List<Integer> groupMemberTypes;\n\n    public InputGetUserGroupByType() {\n    }\n\n    public InputGetUserGroupByType(String userId, List<Integer> groupMemberTypes) {\n        this.userId = userId;\n        this.groupMemberTypes = groupMemberTypes;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public List<Integer> getGroupMemberTypes() {\n        return groupMemberTypes;\n    }\n\n    public void setGroupMemberTypes(List<Integer> groupMemberTypes) {\n        this.groupMemberTypes = groupMemberTypes;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetUserInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputGetUserInfo {\n    private String userId;\n    private String name;\n    private String mobile;\n    private boolean includeDeleted;\n\n    public InputGetUserInfo() {\n    }\n\n    public InputGetUserInfo(String userId, String name, String mobile) {\n        this.userId = userId;\n        this.name = name;\n        this.mobile = mobile;\n    }\n\n    public InputGetUserInfo(String userId, String name, String mobile, boolean includeDeleted) {\n        this.userId = userId;\n        this.name = name;\n        this.mobile = mobile;\n        this.includeDeleted = includeDeleted;\n    }\n\n    public String getMobile() {\n        return mobile;\n    }\n\n    public void setMobile(String mobile) {\n        this.mobile = mobile;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\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 boolean isIncludeDeleted() {\n        return includeDeleted;\n    }\n\n    public void setIncludeDeleted(boolean includeDeleted) {\n        this.includeDeleted = includeDeleted;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetUserList.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class InputGetUserList {\n    public int count;\n    public int offset;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGetUserSK.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputGetUserSK {\n    private String uid;\n    private String cid;\n\n    public InputGetUserSK(String uid, String cid) {\n        this.uid = uid;\n        this.cid = cid;\n    }\n\n    public String getUid() {\n        return uid;\n    }\n\n    public void setUid(String uid) {\n        this.uid = uid;\n    }\n\n    public String getCid() {\n        return cid;\n    }\n\n    public void setCid(String cid) {\n        this.cid = cid;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputGroupBase.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport java.util.List;\n\npublic class InputGroupBase {\n    public String operator;\n    public List<Integer> to_lines;\n    public MessagePayload  notify_message;\n    private boolean isMeshMessage;\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public List<Integer> getTo_lines() {\n        return to_lines;\n    }\n\n    public void setTo_lines(List<Integer> to_lines) {\n        this.to_lines = to_lines;\n    }\n\n    public MessagePayload getNotify_message() {\n        return notify_message;\n    }\n\n    public void setNotify_message(MessagePayload notify_message) {\n        this.notify_message = notify_message;\n    }\n\n    public boolean isMeshMessage() {\n        return isMeshMessage;\n    }\n\n    public void setMeshMessage(boolean meshMessage) {\n        isMeshMessage = meshMessage;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputHandleFriendRequest.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputHandleFriendRequest {\n    private String userId;\n    private String friendUid;\n    private int status;\n    private boolean force;\n\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getFriendUid() {\n        return friendUid;\n    }\n\n    public void setFriendUid(String friendUid) {\n        this.friendUid = friendUid;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n\n    public boolean isForce() {\n        return force;\n    }\n\n    public void setForce(boolean force) {\n        this.force = force;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputIntValue.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class InputIntValue {\n    public int value;\n\n    public int getValue() {\n        return value;\n    }\n\n    public void setValue(int value) {\n        this.value = value;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputKickoffGroupMember.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class InputKickoffGroupMember extends InputGroupBase {\n    private String group_id;\n    private List<String> members;\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public List<String> getMembers() {\n        return members;\n    }\n\n    public void setMembers(List<String> members) {\n        this.members = members;\n    }\n\n    public boolean isValide() {\n        if (StringUtil.isNullOrEmpty(group_id) || StringUtil.isNullOrEmpty(operator) || members == null || members.isEmpty())\n            return false;\n        return true;\n    }\n\n    public WFCMessage.RemoveGroupMemberRequest toProtoGroupRequest() {\n        WFCMessage.RemoveGroupMemberRequest.Builder removedGroupBuilder = WFCMessage.RemoveGroupMemberRequest.newBuilder();\n        removedGroupBuilder.setGroupId(group_id);\n        removedGroupBuilder.addAllRemovedMember(members);\n\n        if (to_lines != null) {\n            for (Integer line : to_lines\n            ) {\n                removedGroupBuilder.addToLine(line);\n            }\n        }\n\n        if (notify_message != null) {\n            removedGroupBuilder.setNotifyContent(notify_message.toProtoMessageContent());\n        }\n        return removedGroupBuilder.build();\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputMessageUid.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class InputMessageUid {\n    public long messageUid;\n\n    public InputMessageUid() {\n    }\n\n    public InputMessageUid(long messageUid) {\n        this.messageUid = messageUid;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputModifyChannelInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.Arrays;\n\npublic class InputModifyChannelInfo {\n    private int type;\n    private String value;\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public String getValue() {\n        return value;\n    }\n\n    public void setValue(String value) {\n        this.value = value;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputModifyGroupInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class InputModifyGroupInfo extends InputGroupBase {\n    private String group_id;\n    //ModifyGroupInfoType\n    private int type;\n    private String value;\n\n    public boolean isValide() {\n        if (StringUtil.isNullOrEmpty(group_id) || StringUtil.isNullOrEmpty(operator))\n            return false;\n        return true;\n    }\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public String getValue() {\n        return value;\n    }\n\n    public void setValue(String value) {\n        this.value = value;\n    }\n\n    public WFCMessage.ModifyGroupInfoRequest toProtoGroupRequest() {\n        if(notify_message != null && notify_message.getType() > 0) {\n            return WFCMessage.ModifyGroupInfoRequest.newBuilder()\n                .setGroupId(group_id)\n                .setType(type)\n                .setValue(value == null ? \"\" : value)\n                .addAllToLine(to_lines == null || to_lines.isEmpty() ? Arrays.asList(0) : to_lines)\n                .setNotifyContent(notify_message.toProtoMessageContent())\n                .build();\n        } else {\n            return WFCMessage.ModifyGroupInfoRequest.newBuilder()\n                .setGroupId(group_id)\n                .setType(type)\n                .setValue(value == null ? \"\" : value)\n                .addAllToLine(to_lines == null || to_lines.isEmpty() ? Arrays.asList(0) : to_lines)\n                .build();\n        }\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputMuteGroupMember.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class InputMuteGroupMember extends InputGroupBase {\n    private String group_id;\n    private List<String> members;\n    private boolean is_manager;\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public List<String> getMembers() {\n        return members;\n    }\n\n    public void setMembers(List<String> members) {\n        this.members = members;\n    }\n\n    public boolean isIs_manager() {\n        return is_manager;\n    }\n\n    public void setIs_manager(boolean is_manager) {\n        this.is_manager = is_manager;\n    }\n\n    public boolean isValide() {\n        if (StringUtil.isNullOrEmpty(operator) || StringUtil.isNullOrEmpty(group_id) || members == null || members.isEmpty()) {\n            return false;\n        }\n        return true;\n    }\n\n    public WFCMessage.SetGroupManagerRequest toProtoGroupRequest() {\n        WFCMessage.SetGroupManagerRequest.Builder addGroupBuilder = WFCMessage.SetGroupManagerRequest.newBuilder();\n        addGroupBuilder.setGroupId(group_id);\n        addGroupBuilder.addAllUserId(members);\n        addGroupBuilder.setType(is_manager ? 1 : 0);\n\n        if (to_lines != null) {\n            for (Integer line : to_lines\n            ) {\n                addGroupBuilder.addToLine(line);\n            }\n        }\n\n        if (notify_message != null) {\n            addGroupBuilder.setNotifyContent(notify_message.toProtoMessageContent());\n        }\n        return addGroupBuilder.build();\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputOutputDomainInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputOutputDomainInfo {\n    public String domainId;\n    public String name;\n    public String desc;\n    public String email;\n    public String tel;\n    public String address;\n    public String extra;\n    public long dt;\n\n    public String getDomainId() {\n        return domainId;\n    }\n\n    public void setDomainId(String domainId) {\n        this.domainId = domainId;\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 String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public String getTel() {\n        return tel;\n    }\n\n    public void setTel(String tel) {\n        this.tel = tel;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public long getDt() {\n        return dt;\n    }\n\n    public void setDt(long dt) {\n        this.dt = dt;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputOutputDomainInfoList.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport java.util.List;\n\npublic class InputOutputDomainInfoList {\n    public List<InputOutputDomainInfo> infos;\n\n    public List<InputOutputDomainInfo> getInfos() {\n        return infos;\n    }\n\n    public void setInfos(List<InputOutputDomainInfo> infos) {\n        this.infos = infos;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputOutputSensitiveWords.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport java.util.List;\n\npublic class InputOutputSensitiveWords {\n    private List<String> words;\n\n    public List<String> getWords() {\n        return words;\n    }\n\n    public void setWords(List<String> words) {\n        this.words = words;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputOutputUserBlockStatus.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputOutputUserBlockStatus {\n    private String userId;\n    private int status;\n\n    public InputOutputUserBlockStatus() {\n    }\n\n    public InputOutputUserBlockStatus(String userId, int status) {\n        this.userId = userId;\n        this.status = status;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputOutputUserInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\n\n/**\n * 用户信息类\n * <p>\n * 封装用户的所有信息，包括：\n * <ul>\n * <li>用户ID、用户名、显示名称</li>\n * <li>头像、性别</li>\n * <li>手机号、邮箱、地址</li>\n * <li>公司、社交信息</li>\n * <li>用户类型、删除状态</li>\n * <li>更新时间</li>\n * <li>额外扩展信息</li>\n * </ul>\n * </p>\n */\npublic class InputOutputUserInfo {\n    private String userId;\n    private String name;\n    private String password;\n    private String displayName;\n    private String portrait;\n    private int gender;\n    private String mobile;\n    private String email;\n    private String address;\n    private String company;\n    private String social;\n    private String extra;\n    private int type;\n    private int deleted;\n    private long updateDt;\n\n    public static InputOutputUserInfo fromPbUser(WFCMessage.User pbUser) {\n        InputOutputUserInfo inputCreateUser = new InputOutputUserInfo();\n        inputCreateUser.userId = pbUser.getUid();\n        inputCreateUser.name = pbUser.getName();\n        inputCreateUser.displayName = pbUser.getDisplayName();\n        inputCreateUser.portrait = pbUser.getPortrait();\n        inputCreateUser.gender = pbUser.getGender();\n        inputCreateUser.mobile = pbUser.getMobile();\n        inputCreateUser.email = pbUser.getEmail();\n        inputCreateUser.address = pbUser.getAddress();\n        inputCreateUser.company = pbUser.getCompany();\n        inputCreateUser.social = pbUser.getSocial();\n        inputCreateUser.extra = pbUser.getExtra();\n        inputCreateUser.type = pbUser.getType();\n        inputCreateUser.updateDt = pbUser.getUpdateDt();\n        inputCreateUser.deleted = pbUser.getDeleted();\n        return inputCreateUser;\n    }\n\n    public String getSocial() {\n        return social;\n    }\n\n    public void setSocial(String social) {\n        this.social = social;\n    }\n\n    public WFCMessage.User toUser() {\n        WFCMessage.User.Builder newUserBuilder = WFCMessage.User.newBuilder()\n            .setUid(userId);\n        if (name != null)\n            newUserBuilder.setName(name);\n        if (displayName != null)\n            newUserBuilder.setDisplayName(displayName);\n        if (getPortrait() != null)\n            newUserBuilder.setPortrait(getPortrait());\n        if (getEmail() != null)\n            newUserBuilder.setEmail(getEmail());\n        if (getAddress() != null)\n            newUserBuilder.setAddress(getAddress());\n        if (getCompany() != null)\n            newUserBuilder.setCompany(getCompany());\n        if (getSocial() != null)\n            newUserBuilder.setSocial(getSocial());\n\n        if (getMobile() != null)\n            newUserBuilder.setMobile(getMobile());\n        if (getExtra() != null)\n            newUserBuilder.setExtra(getExtra());\n        newUserBuilder.setGender(gender);\n        newUserBuilder.setType(type);\n        newUserBuilder.setDeleted(deleted);\n\n        newUserBuilder.setUpdateDt(System.currentTimeMillis());\n        return newUserBuilder.build();\n    }\n\n    public long getUpdateDt() {\n        return updateDt;\n    }\n\n    public void setUpdateDt(long updateDt) {\n        this.updateDt = updateDt;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\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 String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    public void setDisplayName(String displayName) {\n        this.displayName = displayName;\n    }\n\n    public String getPortrait() {\n        return portrait;\n    }\n\n    public void setPortrait(String portrait) {\n        this.portrait = portrait;\n    }\n\n    public String getMobile() {\n        return mobile;\n    }\n\n    public void setMobile(String mobile) {\n        this.mobile = mobile;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    public String getCompany() {\n        return company;\n    }\n\n    public void setCompany(String company) {\n        this.company = company;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public int getGender() {\n        return gender;\n    }\n\n    public void setGender(int gender) {\n        this.gender = gender;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public int getDeleted() {\n        return deleted;\n    }\n\n    public void setDeleted(int deleted) {\n        this.deleted = deleted;\n    }\n\n    @Override\n    public String toString() {\n        return \"{\" +\n            \"userId='\" + userId + '\\'' +\n            \", name='\" + name + '\\'' +\n            \", displayName='\" + displayName + '\\'' +\n            \", portrait='\" + portrait + '\\'' +\n            \", mobile='\" + mobile + '\\'' +\n            \", updateDt=\" + updateDt +\n            '}';\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputQuitGroup.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class InputQuitGroup extends InputGroupBase {\n    private String group_id;\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public boolean isValide() {\n        if (StringUtil.isNullOrEmpty(group_id) || StringUtil.isNullOrEmpty(operator))\n            return false;\n        return true;\n    }\n\n    public WFCMessage.QuitGroupRequest toProtoGroupRequest() {\n        WFCMessage.QuitGroupRequest.Builder removedGroupBuilder = WFCMessage.QuitGroupRequest.newBuilder();\n        removedGroupBuilder.setGroupId(group_id);\n\n        if (to_lines != null) {\n            for (Integer line : to_lines\n            ) {\n                removedGroupBuilder.addToLine(line);\n            }\n        }\n\n        if (notify_message != null) {\n            removedGroupBuilder.setNotifyContent(notify_message.toProtoMessageContent());\n        }\n        return removedGroupBuilder.build();\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputRobotId.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputRobotId {\n    private String robotId;\n\n    public String getRobotId() {\n        return robotId;\n    }\n\n    public void setRobotId(String robotId) {\n        this.robotId = robotId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputSetChatroomBlacklist.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputSetChatroomBlacklist {\n    private String chatroomId;\n    private String userId;\n    private int status;\n    private long expiredTime;\n\n    public InputSetChatroomBlacklist() {\n    }\n\n    public InputSetChatroomBlacklist(String chatroomId, String userId, int status, long expiredTime) {\n        this.chatroomId = chatroomId;\n        this.userId = userId;\n        this.status = status;\n        this.expiredTime = expiredTime;\n    }\n\n    public String getChatroomId() {\n        return chatroomId;\n    }\n\n    public void setChatroomId(String chatroomId) {\n        this.chatroomId = chatroomId;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n\n    public long getExpiredTime() {\n        return expiredTime;\n    }\n\n    public void setExpiredTime(long expiredTime) {\n        this.expiredTime = expiredTime;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputSetChatroomManager.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputSetChatroomManager {\n    private String chatroomId;\n    private String userId;\n    private int status;\n\n    public InputSetChatroomManager() {\n    }\n\n    public InputSetChatroomManager(String chatroomId, String userId, int status) {\n        this.chatroomId = chatroomId;\n        this.userId = userId;\n        this.status = status;\n    }\n\n    public String getChatroomId() {\n        return chatroomId;\n    }\n\n    public void setChatroomId(String chatroomId) {\n        this.chatroomId = chatroomId;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputSetGroupManager.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class InputSetGroupManager extends InputGroupBase {\n    private String group_id;\n    private List<String> members;\n    private boolean is_manager;\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public List<String> getMembers() {\n        return members;\n    }\n\n    public void setMembers(List<String> members) {\n        this.members = members;\n    }\n\n    public boolean isIs_manager() {\n        return is_manager;\n    }\n\n    public void setIs_manager(boolean is_manager) {\n        this.is_manager = is_manager;\n    }\n\n    public boolean isValide() {\n        if (StringUtil.isNullOrEmpty(operator) || StringUtil.isNullOrEmpty(group_id) || members == null || members.isEmpty()) {\n            return false;\n        }\n        return true;\n    }\n\n    public WFCMessage.SetGroupManagerRequest toProtoGroupRequest() {\n        WFCMessage.SetGroupManagerRequest.Builder addGroupBuilder = WFCMessage.SetGroupManagerRequest.newBuilder();\n        addGroupBuilder.setGroupId(group_id);\n        addGroupBuilder.addAllUserId(members);\n        addGroupBuilder.setType(is_manager ? 1 : 0);\n\n        if (to_lines != null) {\n            for (Integer line : to_lines\n            ) {\n                addGroupBuilder.addToLine(line);\n            }\n        }\n\n        if (notify_message != null) {\n            addGroupBuilder.setNotifyContent(notify_message.toProtoMessageContent());\n        }\n        return addGroupBuilder.build();\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputSetGroupMemberAlias.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class InputSetGroupMemberAlias extends InputGroupBase {\n    private String group_id;\n    private String memberId;\n    private String alias;\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public boolean isValide() {\n        return true;\n    }\n\n    public WFCMessage.ModifyGroupMemberAlias toProtoGroupRequest() {\n        WFCMessage.ModifyGroupMemberAlias.Builder modifyAliasBuilder = WFCMessage.ModifyGroupMemberAlias.newBuilder();\n        modifyAliasBuilder.setGroupId(group_id);\n        modifyAliasBuilder.setAlias(StringUtil.isNullOrEmpty(alias)?\"\":alias);\n        modifyAliasBuilder.setMemberId(memberId);\n\n        if (to_lines != null) {\n            for (Integer line : to_lines) {\n                modifyAliasBuilder.addToLine(line);\n            }\n        }\n\n        if (notify_message != null) {\n            modifyAliasBuilder.setNotifyContent(notify_message.toProtoMessageContent());\n        }\n        return modifyAliasBuilder.build();\n    }\n\n    public String getMemberId() {\n        return memberId;\n    }\n\n    public void setMemberId(String memberId) {\n        this.memberId = memberId;\n    }\n\n    public String getAlias() {\n        return alias;\n    }\n\n    public void setAlias(String alias) {\n        this.alias = alias;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputSetGroupMemberExtra.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\npublic class InputSetGroupMemberExtra extends InputGroupBase {\n    private String group_id;\n    private String memberId;\n    private String extra;\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public boolean isValide() {\n        return true;\n    }\n\n    public WFCMessage.ModifyGroupMemberExtra toProtoGroupRequest() {\n        WFCMessage.ModifyGroupMemberExtra.Builder modifyAliasBuilder = WFCMessage.ModifyGroupMemberExtra.newBuilder();\n        modifyAliasBuilder.setGroupId(group_id);\n        modifyAliasBuilder.setMemberId(memberId);\n        modifyAliasBuilder.setExtra(StringUtil.isNullOrEmpty(extra)?\"\": extra);\n\n        if (to_lines != null) {\n            for (Integer line : to_lines) {\n                modifyAliasBuilder.addToLine(line);\n            }\n        }\n\n        if (notify_message != null) {\n            modifyAliasBuilder.setNotifyContent(notify_message.toProtoMessageContent());\n        }\n        return modifyAliasBuilder.build();\n    }\n\n    public String getMemberId() {\n        return memberId;\n    }\n\n    public void setMemberId(String memberId) {\n        this.memberId = memberId;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputStringList.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class InputStringList {\n    private List<String> list;\n\n    public InputStringList() {\n    }\n\n    public InputStringList(List<String> list) {\n        this.list = list;\n    }\n\n    public List<String> getList() {\n        return list;\n    }\n\n    public void setList(List<String> list) {\n        this.list = list;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputStringValue.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class InputStringValue {\n    public String value;\n\n    public String getValue() {\n        return value;\n    }\n\n    public void setValue(String value) {\n        this.value = value;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputSubscribeChannel.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputSubscribeChannel {\n    private String channelId;\n    private String userId;\n    private int subscribe; //1，订阅；0，取消订阅\n\n    public InputSubscribeChannel() {\n    }\n\n    public InputSubscribeChannel(String channelId, String userId, int subscribe) {\n        this.channelId = channelId;\n        this.userId = userId;\n        this.subscribe = subscribe;\n    }\n\n    public String getChannelId() {\n        return channelId;\n    }\n\n    public void setChannelId(String channelId) {\n        this.channelId = channelId;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public int getSubscribe() {\n        return subscribe;\n    }\n\n    public void setSubscribe(int subscribe) {\n        this.subscribe = subscribe;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputTransferGroup.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\npublic class InputTransferGroup extends InputGroupBase {\n    private String group_id;\n    private String new_owner;\n\n\n    public boolean isValide() {\n        if (StringUtil.isNullOrEmpty(group_id) || StringUtil.isNullOrEmpty(operator) || StringUtil.isNullOrEmpty(new_owner))\n            return false;\n        return true;\n    }\n\n    public WFCMessage.TransferGroupRequest toProtoGroupRequest() {\n        WFCMessage.TransferGroupRequest.Builder groupBuilder = WFCMessage.TransferGroupRequest.newBuilder();\n\n        groupBuilder.setGroupId(group_id);\n        groupBuilder.setNewOwner(new_owner);\n        if (to_lines != null) {\n            for (Integer line : to_lines\n            ) {\n                groupBuilder.addToLine(line);\n            }\n        }\n\n        if (notify_message != null) {\n            groupBuilder.setNotifyContent(notify_message.toProtoMessageContent());\n        }\n        return groupBuilder.build();\n    }\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public String getNew_owner() {\n        return new_owner;\n    }\n\n    public void setNew_owner(String new_owner) {\n        this.new_owner = new_owner;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputUpdateAlias.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputUpdateAlias {\n    private String operator;\n    private String targetId;\n    private String alias;\n\n    public String getTargetId() {\n        return targetId;\n    }\n\n    public void setTargetId(String targetId) {\n        this.targetId = targetId;\n    }\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public String getAlias() {\n        return alias;\n    }\n\n    public void setAlias(String alias) {\n        this.alias = alias;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputUpdateFriendExtra.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputUpdateFriendExtra {\n    private String operator;\n    private String targetId;\n    private String extra;\n\n    public String getTargetId() {\n        return targetId;\n    }\n\n    public void setTargetId(String targetId) {\n        this.targetId = targetId;\n    }\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputUpdateFriendStatusRequest.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputUpdateFriendStatusRequest {\n    private String userId;\n    private String friendUid;\n    private int status;\n    private String extra;\n\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getFriendUid() {\n        return friendUid;\n    }\n\n    public void setFriendUid(String friendUid) {\n        this.friendUid = friendUid;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputUpdateUserInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\n\npublic class InputUpdateUserInfo {\n    //UpdateUserInfoMask\n    public int flag;\n    public InputOutputUserInfo userInfo;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputUserConversation.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class InputUserConversation {\n    public String userId;\n    public Conversation conversation;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputUserId.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class InputUserId {\n    private String userId;\n\n    public InputUserId() {\n    }\n\n    public InputUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/InputUserLogin.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class InputUserLogin {\n    private String name;\n    private String password;\n    private String clientId;\n\n    public String getClientId() {\n        return clientId;\n    }\n\n    public void setClientId(String clientId) {\n        this.clientId = clientId;\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 String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/IntStringPairPojo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class IntStringPairPojo {\n    private int intValue;\n    private String strValue;\n\n    public IntStringPairPojo() {\n    }\n\n    public IntStringPairPojo(int intValue, String strValue) {\n        this.intValue = intValue;\n        this.strValue = strValue;\n    }\n\n    public int getIntValue() {\n        return intValue;\n    }\n\n    public void setIntValue(int intValue) {\n        this.intValue = intValue;\n    }\n\n    public String getStrValue() {\n        return strValue;\n    }\n\n    public void setStrValue(String strValue) {\n        this.strValue = strValue;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/LongPojo.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class LongPojo {\n    public long value;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/MessagePayload.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport com.google.protobuf.ByteString;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.Base64;\nimport java.util.List;\n\n/**\n * 消息内容负载类\n * <p>\n * 封装消息的所有内容信息，包括：\n * <ul>\n * <li>消息类型</li>\n * <li>可搜索内容（文本消息的文本）</li>\n * <li>推送内容和推送数据</li>\n * <li>消息内容（二进制数据）</li>\n * <li>媒体类型和远程URL</li>\n * <li>持久化标志和过期时间</li>\n * <li>@提及信息</li>\n * <li>额外数据</li>\n * </ul>\n * </p>\n */\npublic class MessagePayload {\n    private int type;\n    private String searchableContent;\n    private String pushContent;\n    private String pushData;\n    private String content;\n    private String base64edData;\n    private int mediaType;\n    private String remoteMediaUrl;\n    private int persistFlag;\n    private int expireDuration;\n    private int mentionedType;\n    private List<String> mentionedTarget;\n    private String extra;\n\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public String getSearchableContent() {\n        return searchableContent;\n    }\n\n    public void setSearchableContent(String searchableContent) {\n        this.searchableContent = searchableContent;\n    }\n\n    public String getPushContent() {\n        return pushContent;\n    }\n\n    public void setPushContent(String pushContent) {\n        this.pushContent = pushContent;\n    }\n\n    public String getContent() {\n        return content;\n    }\n\n    public void setContent(String content) {\n        this.content = content;\n    }\n\n    public String getBase64edData() {\n        return base64edData;\n    }\n\n    public void setBase64edData(String base64edData) {\n        this.base64edData = base64edData;\n    }\n\n    public int getMediaType() {\n        return mediaType;\n    }\n\n    public void setMediaType(int mediaType) {\n        this.mediaType = mediaType;\n    }\n\n    public String getRemoteMediaUrl() {\n        return remoteMediaUrl;\n    }\n\n    public void setRemoteMediaUrl(String remoteMediaUrl) {\n        this.remoteMediaUrl = remoteMediaUrl;\n    }\n\n    public int getPersistFlag() {\n        return persistFlag;\n    }\n\n    public void setPersistFlag(int persistFlag) {\n        this.persistFlag = persistFlag;\n    }\n\n    public int getExpireDuration() {\n        return expireDuration;\n    }\n\n    public void setExpireDuration(int expireDuration) {\n        this.expireDuration = expireDuration;\n    }\n\n    public int getMentionedType() {\n        return mentionedType;\n    }\n\n    public void setMentionedType(int mentionedType) {\n        this.mentionedType = mentionedType;\n    }\n\n    public List<String> getMentionedTarget() {\n        return mentionedTarget;\n    }\n\n    public void setMentionedTarget(List<String> mentionedTarget) {\n        this.mentionedTarget = mentionedTarget;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public String getPushData() {\n        return pushData;\n    }\n\n    public void setPushData(String pushData) {\n        this.pushData = pushData;\n    }\n\n    public WFCMessage.MessageContent toProtoMessageContent() {\n        WFCMessage.MessageContent.Builder builder = WFCMessage.MessageContent.newBuilder()\n            .setType(type)\n            .setMediaType(mediaType)\n            .setPersistFlag(persistFlag)\n            .setExpireDuration(expireDuration)\n            .setMentionedType(mentionedType);\n\n        if (!StringUtil.isNullOrEmpty(searchableContent))\n            builder.setSearchableContent(searchableContent);\n        if (!StringUtil.isNullOrEmpty(pushContent))\n            builder.setPushContent(pushContent);\n        if (!StringUtil.isNullOrEmpty(content))\n            builder.setContent(content);\n        if (!StringUtil.isNullOrEmpty(base64edData))\n            builder.setData(ByteString.copyFrom(Base64.getDecoder().decode(base64edData)));\n        if (!StringUtil.isNullOrEmpty(remoteMediaUrl))\n            builder.setRemoteMediaUrl(remoteMediaUrl);\n        if (mentionedTarget != null && mentionedTarget.size() > 0)\n            builder.addAllMentionedTarget(mentionedTarget);\n        if (!StringUtil.isNullOrEmpty(extra))\n            builder.setExtra(extra);\n        if (!StringUtil.isNullOrEmpty(pushData))\n            builder.setPushData(pushData);\n\n        return builder.build();\n    }\n\n    public static MessagePayload fromProtoMessageContent(WFCMessage.MessageContent protoContent) {\n        if (protoContent == null)\n            return null;\n\n        MessagePayload payload = new MessagePayload();\n        payload.type = protoContent.getType();\n        payload.searchableContent = protoContent.getSearchableContent();\n        payload.pushContent = protoContent.getPushContent();\n        payload.content = protoContent.getContent();\n        if (protoContent.getData() != null && protoContent.getData().size() > 0)\n            payload.base64edData = Base64.getEncoder().encodeToString(protoContent.getData().toByteArray());\n        payload.mediaType = protoContent.getMediaType();\n        payload.remoteMediaUrl = protoContent.getRemoteMediaUrl();\n        payload.persistFlag = protoContent.getPersistFlag();\n        payload.expireDuration = protoContent.getExpireDuration();\n        payload.mentionedType = protoContent.getMentionedType();\n        payload.mentionedTarget = new ArrayList<>();\n        payload.mentionedTarget.addAll(protoContent.getMentionedTargetList());\n        payload.extra = protoContent.getExtra();\n        payload.pushData = protoContent.getPushData();\n        return payload;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/MultiMessageResult.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class MultiMessageResult {\n    private long messageUid;\n    private long timestamp;\n\n    public MultiMessageResult() {\n    }\n\n    public MultiMessageResult(long messageUid, long timestamp) {\n        this.messageUid = messageUid;\n        this.timestamp = timestamp;\n    }\n\n    public long getMessageUid() {\n        return messageUid;\n    }\n\n    public void setMessageUid(long messageUid) {\n        this.messageUid = messageUid;\n    }\n\n    public long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(long timestamp) {\n        this.timestamp = timestamp;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/MulticastMessageData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class MulticastMessageData {\n    private String sender;\n    private int line;\n    private MessagePayload payload;\n    private List<String> targets;\n\n    public String getSender() {\n        return sender;\n    }\n\n    public void setSender(String sender) {\n        this.sender = sender;\n    }\n\n    public int getLine() {\n        return line;\n    }\n\n    public void setLine(int line) {\n        this.line = line;\n    }\n\n    public MessagePayload getPayload() {\n        return payload;\n    }\n\n    public void setPayload(MessagePayload payload) {\n        this.payload = payload;\n    }\n\n    public static boolean isValide(MulticastMessageData sendMessageData) {\n        if(sendMessageData == null ||\n            StringUtil.isNullOrEmpty(sendMessageData.getSender()) ||\n            sendMessageData.getPayload() == null) {\n            return false;\n        }\n        return true;\n    }\n\n    public WFCMessage.MultiCastMessage toProtoMessage() {\n        return WFCMessage.MultiCastMessage.newBuilder().setFromUser(sender)\n            .setLine(line)\n            .setContent(payload.toProtoMessageContent())\n            .addAllTo(targets)\n            .build();\n    }\n\n    public List<String> getTargets() {\n        return targets;\n    }\n\n    public void setTargets(List<String> targets) {\n        this.targets = targets;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/MyInfoType.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic interface MyInfoType {\n    int Modify_DisplayName = 0;\n    int Modify_Portrait = 1;\n    int Modify_Gender = 2;\n    int Modify_Mobile = 3;\n    int Modify_Email = 4;\n    int Modify_Address = 5;\n    int Modify_Company = 6;\n    int Modify_Social = 7;\n    int Modify_Extra = 8;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputApplicationConfigData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class OutputApplicationConfigData {\n    private String appId;\n    private int appType;\n    private long timestamp;\n    private String nonceStr;\n    private String signature;\n\n    public String getAppId() {\n        return appId;\n    }\n\n    public void setAppId(String appId) {\n        this.appId = appId;\n    }\n\n    public int getAppType() {\n        return appType;\n    }\n\n    public void setAppType(int appType) {\n        this.appType = appType;\n    }\n\n    public long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(long timestamp) {\n        this.timestamp = timestamp;\n    }\n\n    public String getNonceStr() {\n        return nonceStr;\n    }\n\n    public void setNonceStr(String nonceStr) {\n        this.nonceStr = nonceStr;\n    }\n\n    public String getSignature() {\n        return signature;\n    }\n\n    public void setSignature(String signature) {\n        this.signature = signature;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputApplicationUserInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class OutputApplicationUserInfo {\n    private String userId;\n    private String displayName;\n    private String portraitUrl;\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    public void setDisplayName(String displayName) {\n        this.displayName = displayName;\n    }\n\n    public String getPortraitUrl() {\n        return portraitUrl;\n    }\n\n    public void setPortraitUrl(String portraitUrl) {\n        this.portraitUrl = portraitUrl;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputBooleanValue.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class OutputBooleanValue {\n    public boolean value;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputChatroomBlackInfos.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class OutputChatroomBlackInfos {\n    public static class OutputChatroomBlackInfo {\n        public String userId;\n        public int state;\n        public long expiredTime;\n\n        public OutputChatroomBlackInfo() {\n        }\n\n        public OutputChatroomBlackInfo(String userId, int state, long expiredTime) {\n            this.userId = userId;\n            this.state = state;\n            this.expiredTime = expiredTime;\n        }\n    }\n    public List<OutputChatroomBlackInfo> infos = new ArrayList<>();\n    public void addBlackInfo(String userId, int state, long expiredTime) {\n        infos.add(new OutputChatroomBlackInfo(userId, state, expiredTime));\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputCheckUserOnline.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\npublic class OutputCheckUserOnline {\n    public static class Session {\n        public String clientId;\n        public String userId;\n        public int platform;\n        public int status; //0 online, 1 have session offline\n        public long lastSeen;\n        public String packageName;\n        public String ip;\n\n        public Session() {\n        }\n\n        public Session(String clientId, String userId, int platform, int status, long lastSeen, String packageName, String ip) {\n            this.clientId = clientId;\n            this.userId = userId;\n            this.platform = platform;\n            this.status = status;\n            this.lastSeen = lastSeen;\n            this.packageName = packageName;\n            this.ip = ip;\n        }\n    }\n\n    public void addSession(String userId, String clientId, int platform, int status, long lastSeen, String packageName, String ip) {\n        Session session = new Session(clientId, userId, platform, status, lastSeen, packageName, ip);\n        sessions.add(session);\n    }\n\n    private List<Session> sessions = new ArrayList<>();\n\n    public List<Session> getSessions() {\n        return sessions;\n    }\n\n    public void setSessions(List<Session> sessions) {\n        this.sessions = sessions;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputClient.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class OutputClient {\n    private int platform;\n    private String clientId;\n\n    public OutputClient() {\n    }\n\n    public OutputClient(int platform, String clientId) {\n        this.platform = platform;\n        this.clientId = clientId;\n    }\n\n    public int getPlatform() {\n        return platform;\n    }\n\n    public void setPlatform(int platform) {\n        this.platform = platform;\n    }\n\n    public String getClientId() {\n        return clientId;\n    }\n\n    public void setClientId(String clientId) {\n        this.clientId = clientId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputCreateChannel.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\n\npublic class OutputCreateChannel {\n    private String targetId;\n    private String secret;\n\n    public OutputCreateChannel(String targetId, String secret) {\n        this.targetId = targetId;\n        this.secret = secret;\n    }\n\n    public String getTargetId() {\n        return targetId;\n    }\n\n    public void setTargetId(String targetId) {\n        this.targetId = targetId;\n    }\n\n    public String getSecret() {\n        return secret;\n    }\n\n    public void setSecret(String secret) {\n        this.secret = secret;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputCreateChatroom.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class OutputCreateChatroom {\n    private String chatroomId;\n\n    public OutputCreateChatroom() {\n    }\n\n    public OutputCreateChatroom(String chatroomId) {\n        this.chatroomId = chatroomId;\n    }\n\n    public String getChatroomId() {\n        return chatroomId;\n    }\n\n    public void setChatroomId(String chatroomId) {\n        this.chatroomId = chatroomId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputCreateDevice.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class OutputCreateDevice {\n    private String deviceId;\n    private String token;\n    private String secret;\n\n    public OutputCreateDevice() {\n    }\n\n    public OutputCreateDevice(String userId, String token, String secret) {\n        this.deviceId = userId;\n        this.token = token;\n        this.secret = secret;\n    }\n\n    public String getDeviceId() {\n        return deviceId;\n    }\n\n    public void setDeviceId(String deviceId) {\n        this.deviceId = deviceId;\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    public void setToken(String token) {\n        this.token = token;\n    }\n\n    public String getSecret() {\n        return secret;\n    }\n\n    public void setSecret(String secret) {\n        this.secret = secret;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputCreateGroupResult.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class OutputCreateGroupResult {\n    private String group_id;\n\n    public OutputCreateGroupResult(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputCreateRobot.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class OutputCreateRobot {\n    private String userId;\n    private String secret;\n\n    public OutputCreateRobot() {\n    }\n\n    public OutputCreateRobot(String userId, String secret) {\n        this.userId = userId;\n        this.secret = secret;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getSecret() {\n        return secret;\n    }\n\n    public void setSecret(String secret) {\n        this.secret = secret;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputCreateUser.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class OutputCreateUser {\n    private String userId;\n    private String name;\n\n    public OutputCreateUser() {\n    }\n\n    public OutputCreateUser(String userId, String name) {\n        this.userId = userId;\n        this.name = name;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputDevice.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.WFCMessage;\n\nimport java.util.List;\n\npublic class OutputDevice {\n    private int state;\n    private String deviceId;\n    private String token;\n    private String secret;\n    private List<String> owners;\n    private String extra;\n\n    public OutputDevice() {\n    }\n\n    public OutputDevice(String deviceId, String token, String secret) {\n        this.deviceId = deviceId;\n        this.token = token;\n        this.secret = secret;\n    }\n\n    public String getDeviceId() {\n        return deviceId;\n    }\n\n    public void setDeviceId(String deviceId) {\n        this.deviceId = deviceId;\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    public void setToken(String token) {\n        this.token = token;\n    }\n\n    public String getSecret() {\n        return secret;\n    }\n\n    public void setSecret(String secret) {\n        this.secret = secret;\n    }\n\n    public int getState() {\n        return state;\n    }\n\n    public void setState(int state) {\n        this.state = state;\n    }\n\n    public List<String> getOwners() {\n        return owners;\n    }\n\n    public void setOwners(List<String> owners) {\n        this.owners = owners;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputDeviceHost.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class OutputDeviceHost {\n    private String host;\n\n    public String getHost() {\n        return host;\n    }\n\n    public void setHost(String host) {\n        this.host = host;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputDeviceList.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class OutputDeviceList {\n    private List<OutputDevice> devices;\n\n    public List<OutputDevice> getDevices() {\n        return devices;\n    }\n\n    public void setDevices(List<OutputDevice> devices) {\n        this.devices = devices;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputGetAlias.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class OutputGetAlias {\n    private String operator;\n    private String targetId;\n    private String alias;\n\n    public OutputGetAlias() {\n    }\n\n    public OutputGetAlias(String operator, String targetId) {\n        this.operator = operator;\n        this.targetId = targetId;\n    }\n\n    public String getTargetId() {\n        return targetId;\n    }\n\n    public void setTargetId(String targetId) {\n        this.targetId = targetId;\n    }\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public String getAlias() {\n        return alias;\n    }\n\n    public void setAlias(String alias) {\n        this.alias = alias;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputGetChannelInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class OutputGetChannelInfo {\n    public static class OutputMenuList extends ArrayList<PojoChannelMenu> {\n    }\n\n    private String channelId;\n    private String name;\n    private String desc;\n    private String portrait;\n    private String extra;\n    private String owner;\n    private int state;\n    private int status;\n    private long updateDt;\n    private String callback;\n    private int automatic;\n    private String secret;\n    public List<PojoChannelMenu> menus;\n\n    public String getChannelId() {\n        return channelId;\n    }\n\n    public void setChannelId(String channelId) {\n        this.channelId = channelId;\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 String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    public String getPortrait() {\n        return portrait;\n    }\n\n    public void setPortrait(String portrait) {\n        this.portrait = portrait;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public String getOwner() {\n        return owner;\n    }\n\n    public void setOwner(String owner) {\n        this.owner = owner;\n    }\n\n    public int getState() {\n        return state;\n    }\n\n    public void setState(int state) {\n        this.state = state;\n    }\n\n    public long getUpdateDt() {\n        return updateDt;\n    }\n\n    public void setUpdateDt(long updateDt) {\n        this.updateDt = updateDt;\n    }\n\n    public String getCallback() {\n        return callback;\n    }\n\n    public void setCallback(String callback) {\n        this.callback = callback;\n    }\n\n    public int getAutomatic() {\n        return automatic;\n    }\n\n    public void setAutomatic(int automatic) {\n        this.automatic = automatic;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n\n    public String getSecret() {\n        return secret;\n    }\n\n    public void setSecret(String secret) {\n        this.secret = secret;\n    }\n\n    public static OutputGetChannelInfo fromPbInfo(WFCMessage.ChannelInfo channelInfo) {\n        OutputGetChannelInfo out = new OutputGetChannelInfo();\n        out.automatic = channelInfo.getAutomatic();\n        out.callback = channelInfo.getCallback();\n        out.channelId = channelInfo.getTargetId();\n        out.desc = channelInfo.getDesc();\n        out.extra = channelInfo.getExtra();\n        out.name = channelInfo.getName();\n        out.owner = channelInfo.getOwner();\n        out.portrait = channelInfo.getPortrait();\n        out.state = channelInfo.getStatus();\n        out.status = channelInfo.getStatus();;\n        out.updateDt = channelInfo.getUpdateDt();\n        out.secret = channelInfo.getSecret();\n        if (channelInfo.getMenuCount() > 0) {\n            out.menus = new ArrayList<>();\n            for (WFCMessage.ChannelMenu channelMenuMenu : channelInfo.getMenuList()) {\n                out.menus.add(PojoChannelMenu.fromPbInfo(channelMenuMenu));\n            }\n        }\n        return out;\n    }\n}\n\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputGetChatroomInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\npublic class OutputGetChatroomInfo {\n    private String chatroomId;\n    private String title;\n    private String desc;\n    private String portrait;\n    private String extra;\n    private int state;\n    private int memberCount;\n    private long createDt;\n    private long updateDt;\n\n    public OutputGetChatroomInfo(String chatroomId, int memberCount, WFCMessage.ChatroomInfo chatroomInfo) {\n        this.chatroomId = chatroomId;\n        this.title = chatroomInfo.getTitle();\n        this.desc = chatroomInfo.getDesc();\n        this.portrait = chatroomInfo.getPortrait();\n        this.memberCount = memberCount;\n        this.extra = chatroomInfo.getExtra();\n        this.state = chatroomInfo.getState();\n        this.createDt = chatroomInfo.getCreateDt();\n        this.updateDt = chatroomInfo.getUpdateDt();\n    }\n\n    public OutputGetChatroomInfo() {\n    }\n\n    public int getMemberCount() {\n        return memberCount;\n    }\n\n    public void setMemberCount(int memberCount) {\n        this.memberCount = memberCount;\n    }\n\n    public long getCreateDt() {\n        return createDt;\n    }\n\n    public void setCreateDt(long createDt) {\n        this.createDt = createDt;\n    }\n\n    public long getUpdateDt() {\n        return updateDt;\n    }\n\n    public void setUpdateDt(long updateDt) {\n        this.updateDt = updateDt;\n    }\n\n    public String getChatroomId() {\n        return chatroomId;\n    }\n\n    public void setChatroomId(String chatroomId) {\n        this.chatroomId = chatroomId;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    public String getPortrait() {\n        return portrait;\n    }\n\n    public void setPortrait(String portrait) {\n        this.portrait = portrait;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public int getState() {\n        return state;\n    }\n\n    public void setState(int state) {\n        this.state = state;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputGetFriendList.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport java.util.List;\nimport java.util.Map;\n\npublic class OutputGetFriendList {\n    private List<String> friends;\n\n    public List<String> getFriends() {\n        return friends;\n    }\n\n    public void setFriends(List<String> friends) {\n        this.friends = friends;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputGetIMTokenData.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class OutputGetIMTokenData {\n    private String userId;\n    private String token;\n    private String serverLabel;\n\n    public OutputGetIMTokenData() {\n    }\n\n    public OutputGetIMTokenData(String userId, String imToken, String label) {\n        this.userId = userId;\n        this.token = imToken;\n        this.serverLabel = label;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    public void setToken(String token) {\n        this.token = token;\n    }\n\n    public String getServerLabel() {\n        return serverLabel;\n    }\n\n    public void setServerLabel(String serverLabel) {\n        this.serverLabel = serverLabel;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputGetUserList.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class OutputGetUserList {\n    public List<InputOutputUserInfo> userInfoList;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputGroupIds.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class OutputGroupIds {\n    private List<String> groupIds;\n\n    public List<String> getGroupIds() {\n        return groupIds;\n    }\n\n    public void setGroupIds(List<String> groupIds) {\n        this.groupIds = groupIds;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputGroupMemberList.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class OutputGroupMemberList {\n    private List<PojoGroupMember> members;\n\n    public List<PojoGroupMember> getMembers() {\n        return members;\n    }\n\n    public void setMembers(List<PojoGroupMember> members) {\n        this.members = members;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputLoginData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class OutputLoginData {\n    private String userId;\n    private String token;\n\n    public OutputLoginData() {\n    }\n\n    public OutputLoginData(String userId, String token) {\n        this.userId = userId;\n        this.token = token;\n    }\n\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getToken() {\n        return token;\n    }\n\n    public void setToken(String token) {\n        this.token = token;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputMessageData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class OutputMessageData {\n    private long messageId;\n    private String sender;\n    private Conversation conv;\n    private MessagePayload payload;\n    private List<String> toUsers;\n    private long timestamp;\n    private OutputClient client;\n\n    private InputOutputUserInfo senderUserInfo;\n    private InputOutputUserInfo targetUserInfo;\n    private PojoGroupInfo targetGroupInfo;\n    private OutputGetChannelInfo targetChannelInfo;\n\n    private String toRobotId;\n\n    public String getSender() {\n        return sender;\n    }\n\n    public void setSender(String sender) {\n        this.sender = sender;\n    }\n\n    public Conversation getConv() {\n        return conv;\n    }\n\n    public void setConv(Conversation conv) {\n        this.conv = conv;\n    }\n\n    public MessagePayload getPayload() {\n        return payload;\n    }\n\n    public void setPayload(MessagePayload payload) {\n        this.payload = payload;\n    }\n\n    public List<String> getToUsers() {\n        return toUsers;\n    }\n\n    public void setToUsers(List<String> toUsers) {\n        this.toUsers = toUsers;\n    }\n\n    public long getMessageId() {\n        return messageId;\n    }\n\n    public void setMessageId(long messageId) {\n        this.messageId = messageId;\n    }\n\n    public long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(long timestamp) {\n        this.timestamp = timestamp;\n    }\n\n    public OutputClient getClient() {\n        return client;\n    }\n\n    public void setClient(OutputClient client) {\n        this.client = client;\n    }\n\n    public InputOutputUserInfo getSenderUserInfo() {\n        return senderUserInfo;\n    }\n\n    public void setSenderUserInfo(InputOutputUserInfo senderUserInfo) {\n        this.senderUserInfo = senderUserInfo;\n    }\n\n    public InputOutputUserInfo getTargetUserInfo() {\n        return targetUserInfo;\n    }\n\n    public void setTargetUserInfo(InputOutputUserInfo targetUserInfo) {\n        this.targetUserInfo = targetUserInfo;\n    }\n\n    public PojoGroupInfo getTargetGroupInfo() {\n        return targetGroupInfo;\n    }\n\n    public void setTargetGroupInfo(PojoGroupInfo targetGroupInfo) {\n        this.targetGroupInfo = targetGroupInfo;\n    }\n\n    public OutputGetChannelInfo getTargetChannelInfo() {\n        return targetChannelInfo;\n    }\n\n    public void setTargetChannelInfo(OutputGetChannelInfo targetChannelInfo) {\n        this.targetChannelInfo = targetChannelInfo;\n    }\n\n    public static OutputMessageData fromProtoMessage(WFCMessage.Message protoMessage) {\n        return fromProtoMessage(protoMessage, null);\n    }\n\n    public String getToRobotId() {\n        return toRobotId;\n    }\n\n    public void setToRobotId(String toRobotId) {\n        this.toRobotId = toRobotId;\n    }\n\n    public static OutputMessageData fromProtoMessage(WFCMessage.Message protoMessage, OutputClient fromClient) {\n        OutputMessageData data = new OutputMessageData();\n        data.messageId = protoMessage.getMessageId();\n        data.sender = protoMessage.getFromUser();\n        data.conv = new Conversation();\n        data.conv.setTarget(protoMessage.getConversation().getTarget());\n        data.conv.setType(protoMessage.getConversation().getType());\n        data.conv.setLine(protoMessage.getConversation().getLine());\n        data.payload = MessagePayload.fromProtoMessageContent(protoMessage.getContent());\n        data.timestamp = protoMessage.getServerTimestamp();\n        data.toUsers = protoMessage.getToList();\n        data.client = fromClient;\n        return data;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputNotifyChannelSubscribeStatus.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class OutputNotifyChannelSubscribeStatus {\n    private String userId;\n    private String channelId;\n    private int status;\n\n    public OutputNotifyChannelSubscribeStatus() {\n    }\n\n    public OutputNotifyChannelSubscribeStatus(String userId, String channelId, boolean subscirbed) {\n        this.userId = userId;\n        this.channelId = channelId;\n        this.status = subscirbed ? 1 : 0;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getChannelId() {\n        return channelId;\n    }\n\n    public void setChannelId(String channelId) {\n        this.channelId = channelId;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputPresignedUploadUrl.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\n/**\n * 预签名上传地址\n * <p>\n * 封装预签名上传地址，包括：\n * <ul>\n * <li>上传地址</li>\n * <li>备选上传地址</li>\n * <li>下载地址</li>\n * <li>类型</li>\n * </ul>\n * </p>\n */\npublic class OutputPresignedUploadUrl {\n    public String uploadUrl;\n    public String backupUploadUrl;\n    public String downloadUrl;\n    public int type;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputReadData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\npublic class OutputReadData {\n    public String user;\n    public Conversation conversation;\n    public long readTime;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputRecallMessageData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class OutputRecallMessageData {\n    private OutputMessageData message;\n    private String userId;\n    private long timestamp;\n    private boolean isAdmin;\n\n    public OutputRecallMessageData() {\n    }\n\n    public OutputRecallMessageData(OutputMessageData message, String userId, long timestamp, boolean isAdmin) {\n        this.message = message;\n        this.userId = userId;\n        this.timestamp = timestamp;\n        this.isAdmin = isAdmin;\n    }\n\n    public OutputMessageData getMessage() {\n        return message;\n    }\n\n    public void setMessage(OutputMessageData message) {\n        this.message = message;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(long timestamp) {\n        this.timestamp = timestamp;\n    }\n\n    public boolean isAdmin() {\n        return isAdmin;\n    }\n\n    public void setAdmin(boolean admin) {\n        isAdmin = admin;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputRobot.java",
    "content": "package cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\n\npublic class OutputRobot {\n    private String userId;\n    private String name;\n    private String password;\n    private String displayName;\n    private String portrait;\n    private int gender;\n    private String mobile;\n    private String email;\n    private String address;\n    private String company;\n    private String social;\n    private String extra;\n    private long updateDt;\n\n    private String owner;\n    private String secret;\n    private String callback;\n    private String robotExtra;\n\n    public String getSocial() {\n        return social;\n    }\n\n    public void setSocial(String social) {\n        this.social = social;\n    }\n\n    public long getUpdateDt() {\n        return updateDt;\n    }\n\n    public void setUpdateDt(long updateDt) {\n        this.updateDt = updateDt;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\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 String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getDisplayName() {\n        return displayName;\n    }\n\n    public void setDisplayName(String displayName) {\n        this.displayName = displayName;\n    }\n\n    public String getPortrait() {\n        return portrait;\n    }\n\n    public void setPortrait(String portrait) {\n        this.portrait = portrait;\n    }\n\n    public String getMobile() {\n        return mobile;\n    }\n\n    public void setMobile(String mobile) {\n        this.mobile = mobile;\n    }\n\n    public String getEmail() {\n        return email;\n    }\n\n    public void setEmail(String email) {\n        this.email = email;\n    }\n\n    public String getAddress() {\n        return address;\n    }\n\n    public void setAddress(String address) {\n        this.address = address;\n    }\n\n    public String getCompany() {\n        return company;\n    }\n\n    public void setCompany(String company) {\n        this.company = company;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public int getGender() {\n        return gender;\n    }\n\n    public void setGender(int gender) {\n        this.gender = gender;\n    }\n\n    public String getOwner() {\n        return owner;\n    }\n\n    public void setOwner(String owner) {\n        this.owner = owner;\n    }\n\n    public String getSecret() {\n        return secret;\n    }\n\n    public void setSecret(String secret) {\n        this.secret = secret;\n    }\n\n    public String getCallback() {\n        return callback;\n    }\n\n    public void setCallback(String callback) {\n        this.callback = callback;\n    }\n\n    public String getRobotExtra() {\n        return robotExtra;\n    }\n\n    public void setRobotExtra(String robotExtra) {\n        this.robotExtra = robotExtra;\n    }\n\n    public void fromUser(WFCMessage.User user) {\n        userId = user.getUid();\n        name = user.getName();\n        displayName = user.getDisplayName();\n        portrait = user.getPortrait();\n        gender = user.getGender();\n        mobile = user.getMobile();\n        email = user.getEmail();\n        address = user.getAddress();\n        company = user.getCompany();\n        social = user.getSocial();\n        extra = user.getExtra();\n        updateDt = user.getUpdateDt();\n    }\n    public void fromRobot(WFCMessage.Robot robot, boolean withSecret) {\n        setOwner(robot.getOwner());\n        if(withSecret) {\n            setSecret(robot.getSecret());\n        }\n        setCallback(robot.getCallback());\n        setRobotExtra(robot.getExtra());\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputRouteData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class OutputRouteData { ;\n    private List<String> serverIPs;\n    private int longPort;\n    private int shortPort;\n    private String secret;\n\n    public OutputRouteData() {\n    }\n\n    public OutputRouteData(List<String> serverIPs, int longPort, int shortPort, String secret) {\n        this.serverIPs = serverIPs;\n        this.longPort = longPort;\n        this.shortPort = shortPort;\n        this.secret = secret;\n    }\n\n    public int getLongPort() {\n        return longPort;\n    }\n\n    public void setLongPort(int longPort) {\n        this.longPort = longPort;\n    }\n\n    public int getShortPort() {\n        return shortPort;\n    }\n\n    public void setShortPort(int shortPort) {\n        this.shortPort = shortPort;\n    }\n\n    public List<String> getServerIPs() {\n        return serverIPs;\n    }\n\n    public void setServerIPs(List<String> serverIPs) {\n        this.serverIPs = serverIPs;\n    }\n\n    public String getSecret() {\n        return secret;\n    }\n\n    public void setSecret(String secret) {\n        this.secret = secret;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputStringList.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class OutputStringList {\n    private List<String> list;\n\n    public OutputStringList() {\n    }\n\n    public OutputStringList(List<String> list) {\n        this.list = list;\n    }\n\n    public List<String> getList() {\n        return list;\n    }\n\n    public void setList(List<String> list) {\n        this.list = list;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputTimestamp.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class OutputTimestamp {\n    private long timestamp;\n\n    public OutputTimestamp() {\n    }\n\n    public OutputTimestamp(long timestamp) {\n        this.timestamp = timestamp;\n    }\n\n    public long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(long timestamp) {\n        this.timestamp = timestamp;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputUserBlockStatusList.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport java.util.List;\n\npublic class OutputUserBlockStatusList {\n    private List<InputOutputUserBlockStatus> statusList;\n\n    public List<InputOutputUserBlockStatus> getStatusList() {\n        return statusList;\n    }\n\n    public void setStatusList(List<InputOutputUserBlockStatus> statusList) {\n        this.statusList = statusList;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputUserChatroom.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class OutputUserChatroom {\n    public String userId;\n    public String chatroomId;\n    public String clientId;\n    public int/*ProtoConstants.Platform*/ platform;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputUserInfoList.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n\nimport cn.wildfirechat.proto.WFCMessage;\n\nimport java.util.List;\n\npublic class OutputUserInfoList {\n    public List<InputOutputUserInfo> userInfos;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/OutputUserStatus.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class OutputUserStatus {\n    private int status;\n\n    public OutputUserStatus() {\n    }\n\n    public OutputUserStatus(int status) {\n        this.status = status;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoChannelMenu.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class PojoChannelMenu {\n    public String menuId;\n    public String type;\n    public String name;\n    public String key;\n    public String url;\n    public String mediaId;\n    public String articleId;\n    public String appId;\n    public String appPage;\n    public String extra;\n    public List<PojoChannelMenu> subMenus;\n\n    public static PojoChannelMenu fromPbInfo(WFCMessage.ChannelMenu channelMenuMenu) {\n        PojoChannelMenu out = new PojoChannelMenu();\n        out.menuId = channelMenuMenu.getMenuId();\n        out.type = channelMenuMenu.getType();\n        out.name = channelMenuMenu.getName();\n        out.key = channelMenuMenu.getKey();\n        out.url = channelMenuMenu.getUrl();\n        out.mediaId = channelMenuMenu.getMediaId();\n        out.articleId = channelMenuMenu.getArticleId();\n        out.appId = channelMenuMenu.getAppId();\n        out.appPage = channelMenuMenu.getAppPage();\n        out.extra = channelMenuMenu.getExtra();\n        if (channelMenuMenu.getSubMenuCount() > 0) {\n            out.subMenus = new ArrayList<>();\n            for (WFCMessage.ChannelMenu menuMenu : channelMenuMenu.getSubMenuList()) {\n                out.subMenus.add(fromPbInfo(menuMenu));\n            }\n        }\n        return out;\n    }\n\n    public WFCMessage.ChannelMenu.Builder toPbInfo() {\n        WFCMessage.ChannelMenu.Builder builder = WFCMessage.ChannelMenu.newBuilder();\n        builder.setType(type);\n        builder.setName(name);\n        if (!StringUtil.isNullOrEmpty(menuId)) builder.setMenuId(menuId);\n        if (!StringUtil.isNullOrEmpty(key)) builder.setKey(key);\n        if (!StringUtil.isNullOrEmpty(url)) builder.setUrl(url);\n        if (!StringUtil.isNullOrEmpty(mediaId)) builder.setMediaId(mediaId);\n        if (!StringUtil.isNullOrEmpty(articleId)) builder.setArticleId(articleId);\n        if (!StringUtil.isNullOrEmpty(appId)) builder.setAppId(appId);\n        if (!StringUtil.isNullOrEmpty(appPage)) builder.setAppPage(appPage);\n        if (!StringUtil.isNullOrEmpty(extra)) builder.setExtra(extra);\n        if (subMenus != null && !subMenus.isEmpty()) {\n            subMenus.forEach(menuMenu -> builder.addSubMenu(menuMenu.toPbInfo()));\n        }\n        return builder;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoConferenceCreate.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class PojoConferenceCreate {\n    public String roomId;\n    public String description;\n    public String pin;\n    public int max_publishers;\n    public int bitrate;\n    public boolean advance;\n    public boolean recording;\n    public boolean permanent;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoConferenceInfo.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class PojoConferenceInfo {\n    public String roomId;\n    public String description;\n    public int max_publishers;\n    public boolean advance;\n    public boolean recording;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoConferenceInfoList.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class PojoConferenceInfoList {\n    public PojoConferenceInfoList(List<PojoConferenceInfo> conferenceInfoList) {\n        this.conferenceInfoList = conferenceInfoList;\n    }\n\n    public PojoConferenceInfoList() {\n        conferenceInfoList = new ArrayList<>();\n    }\n\n    public List<PojoConferenceInfo> conferenceInfoList;\n\n    public void addConferenceInfo(PojoConferenceInfo conferenceInfo) {\n        this.conferenceInfoList.add(conferenceInfo);\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoConferenceParticipant.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class PojoConferenceParticipant {\n    public static class Stream {\n        public String type;\n        public String mid;\n        public String codec;\n    }\n\n    public String userId;\n    public boolean publishing;\n    public List<Stream> streams;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoConferenceParticipantList.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class PojoConferenceParticipantList {\n    public PojoConferenceParticipantList(List<PojoConferenceParticipant> participantList) {\n        this.participantList = participantList;\n    }\n\n    public PojoConferenceParticipantList() {\n        participantList = new ArrayList<>();\n    }\n\n    public List<PojoConferenceParticipant> participantList;\n\n    public void addConferenceInfo(PojoConferenceParticipant participant) {\n        this.participantList.add(participant);\n    }\n\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoConferenceRecording.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class PojoConferenceRecording {\n    public String roomId;\n    public boolean recording;\n    public boolean advance;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoConferenceRoomId.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class PojoConferenceRoomId {\n    public String roomId;\n    public boolean advance;\n\n    public PojoConferenceRoomId() {\n    }\n\n    public PojoConferenceRoomId(String roomId, boolean advance) {\n        this.roomId = roomId;\n        this.advance = advance;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoConferenceRtpForwardReq.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class PojoConferenceRtpForwardReq {\n    public String roomId;\n    public String publisherId;\n    public String host;\n    public int audioPort;\n    public int audioPt;\n    public long audioSSRC;\n    public int videoPort;\n    public int videoPt;\n    public long videoSSRC;\n\n    public PojoConferenceRtpForwardReq() {\n    }\n\n    public PojoConferenceRtpForwardReq(String roomId, String publisherId, String host, int audioPort, int audioPt, long audioSSRC, int videoPort, int videoPt, long videoSSRC) {\n        this.roomId = roomId;\n        this.publisherId = publisherId;\n        this.host = host;\n        this.audioPort = audioPort;\n        this.audioPt = audioPt;\n        this.audioSSRC = audioSSRC;\n        this.videoPort = videoPort;\n        this.videoPt = videoPt;\n        this.videoSSRC = videoSSRC;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoConferenceRtpForwarders.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class PojoConferenceRtpForwarders {\n    public static class RtpForwarder {\n        public static class RtpStream {\n            public long streamId;\n            public String type;\n            public String host;\n            public int port;\n            public long ssrc;\n            public int pt;\n        }\n\n        public String publisherId;\n        public List<RtpStream> streams;\n    }\n    public String roomId;\n    public List<RtpForwarder> forwarders;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoConferenceStopRtpForwardReq.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class PojoConferenceStopRtpForwardReq {\n    public String roomId;\n    public String publisherId;\n    public long streamId;\n\n    public PojoConferenceStopRtpForwardReq() {\n    }\n\n    public PojoConferenceStopRtpForwardReq(String roomId, String publisherId, long streamId) {\n        this.roomId = roomId;\n        this.publisherId = publisherId;\n        this.streamId = streamId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoGroup.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.List;\n\n/**\n * 群组对象类\n * <p>\n * 封装创建群组时使用的参数，包含群组信息和成员列表。\n * </p>\n */\npublic class PojoGroup {\n    private PojoGroupInfo group_info;\n    private List<PojoGroupMember> members;\n\n    public PojoGroupInfo getGroup_info() {\n        return group_info;\n    }\n\n    public void setGroup_info(PojoGroupInfo group_info) {\n        this.group_info = group_info;\n    }\n\n    public List<PojoGroupMember> getMembers() {\n        return members;\n    }\n\n    public void setMembers(List<PojoGroupMember> members) {\n        this.members = members;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoGroupInfo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n/**\n * 群组信息类\n * <p>\n * 封装群组的信息，包括：\n * <ul>\n * <li>群组ID、名称、头像、所有者</li>\n * <li>群组类型、成员数量、最大成员数</li>\n * <li>群组设置（禁言、加群方式、私聊、可搜索、历史消息）</li>\n * <li>是否超级群、是否已删除</li>\n * <li>更新时间</li>\n * </ul>\n * </p>\n */\npublic class PojoGroupInfo {\n    String target_id;\n    String name;\n    String portrait;\n    String owner;\n    int type;\n    int member_count;\n    String extra;\n    int mute;\n    int join_type;\n    int private_chat;\n    int searchable;\n    int max_member_count;\n    int history_message;\n    boolean super_group;\n    boolean deleted;\n    long update_dt;\n    long member_update_dt;\n\n    public String getTarget_id() {\n        return target_id;\n    }\n\n    public void setTarget_id(String target_id) {\n        this.target_id = target_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 String getPortrait() {\n        return portrait;\n    }\n\n    public void setPortrait(String portrait) {\n        this.portrait = portrait;\n    }\n\n    public String getOwner() {\n        return owner;\n    }\n\n    public void setOwner(String owner) {\n        this.owner = owner;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public int getMax_member_count() {\n        return max_member_count;\n    }\n\n    public void setMax_member_count(int max_member_count) {\n        this.max_member_count = max_member_count;\n    }\n\n    public int getMute() {\n        return mute;\n    }\n\n    public void setMute(int mute) {\n        this.mute = mute;\n    }\n\n    public int getJoin_type() {\n        return join_type;\n    }\n\n    public void setJoin_type(int join_type) {\n        this.join_type = join_type;\n    }\n\n    public int getPrivate_chat() {\n        return private_chat;\n    }\n\n    public void setPrivate_chat(int private_chat) {\n        this.private_chat = private_chat;\n    }\n\n    public int getSearchable() {\n        return searchable;\n    }\n\n    public void setSearchable(int searchable) {\n        this.searchable = searchable;\n    }\n\n    public int getHistory_message() {\n        return history_message;\n    }\n\n    public void setHistory_message(int history_message) {\n        this.history_message = history_message;\n    }\n\n    public boolean isSuper_group() {\n        return super_group;\n    }\n\n    public void setSuper_group(boolean super_group) {\n        this.super_group = super_group;\n    }\n\n    public boolean isDeleted() {\n        return deleted;\n    }\n\n    public void setDeleted(boolean deleted) {\n        this.deleted = deleted;\n    }\n\n    public long getUpdate_dt() {\n        return update_dt;\n    }\n\n    public void setUpdate_dt(long update_dt) {\n        this.update_dt = update_dt;\n    }\n\n    public int getMember_count() {\n        return member_count;\n    }\n\n    public void setMember_count(int member_count) {\n        this.member_count = member_count;\n    }\n\n    public long getMember_update_dt() {\n        return member_update_dt;\n    }\n\n    public void setMember_update_dt(long member_update_dt) {\n        this.member_update_dt = member_update_dt;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoGroupInfoList.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class PojoGroupInfoList {\n    public List<PojoGroupInfo> groupInfoList;\n\n    public List<PojoGroupInfo> getGroupInfoList() {\n        return groupInfoList;\n    }\n\n    public void setGroupInfoList(List<PojoGroupInfo> groupInfoList) {\n        this.groupInfoList = groupInfoList;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/PojoGroupMember.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\n/**\n * 群组成员类\n * <p>\n * 封装群组成员的信息，包括：\n * <ul>\n * <li>成员ID</li>\n * <li>群组内别名</li>\n * <li>成员类型</li>\n * <li>扩展信息</li>\n * <li>更新时间和创建时间</li>\n * </ul>\n * </p>\n */\npublic class PojoGroupMember {\n    String member_id;\n    String alias;\n    int type;\n    String extra;\n    long updateDt;\n    long createDt;\n\n    public String getMember_id() {\n        return member_id;\n    }\n\n    public void setMember_id(String member_id) {\n        this.member_id = member_id;\n    }\n\n    public String getAlias() {\n        return alias;\n    }\n\n    public void setAlias(String alias) {\n        this.alias = alias;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public String getExtra() {\n        return extra;\n    }\n\n    public void setExtra(String extra) {\n        this.extra = extra;\n    }\n\n    public long getUpdateDt() {\n        return updateDt;\n    }\n\n    public void setUpdateDt(long updateDt) {\n        this.updateDt = updateDt;\n    }\n\n    public long getCreateDt() {\n        return createDt;\n    }\n\n    public void setCreateDt(long createDt) {\n        this.createDt = createDt;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/RecallMessageData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\npublic class RecallMessageData {\n    private String operator;\n    private long messageUid;\n    private boolean isUserRecall;\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public long getMessageUid() {\n        return messageUid;\n    }\n\n    public void setMessageUid(long messageUid) {\n        this.messageUid = messageUid;\n    }\n\n    public boolean isUserRecall() {\n        return isUserRecall;\n    }\n\n    public void setUserRecall(boolean userRecall) {\n        isUserRecall = userRecall;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/RecallMultiCastMessageData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class RecallMultiCastMessageData {\n    public String operator;\n    public long messageUid;\n    public List<String> receivers;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/RelationPojo.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class RelationPojo {\n    public String userId;\n    public String targetId;\n    public boolean isFriend;\n    public boolean isBlacked;\n    public String alias;\n    public String extra;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/RelationUpdateEvent.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class RelationUpdateEvent {\n    public String userId;\n    public String targetId;\n    public int type;\n    public String value;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/ReplyMessageData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class ReplyMessageData {\n    private long messageUid;\n    private MessagePayload payload;\n    private boolean only2Sender;\n\n    public long getMessageUid() {\n        return messageUid;\n    }\n\n    public void setMessageUid(long messageUid) {\n        this.messageUid = messageUid;\n    }\n\n    public MessagePayload getPayload() {\n        return payload;\n    }\n\n    public void setPayload(MessagePayload payload) {\n        this.payload = payload;\n    }\n\n    public boolean isOnly2Sender() {\n        return only2Sender;\n    }\n\n    public void setOnly2Sender(boolean only2Sender) {\n        this.only2Sender = only2Sender;\n    }\n\n    public static boolean isValide(ReplyMessageData sendMessageData) {\n        if(sendMessageData.messageUid <=0  ||\n            sendMessageData.getPayload() == null) {\n            return false;\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/RepublishChannelMessageData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class RepublishChannelMessageData {\n    private List<String> targets;\n    private long messageId;\n\n    public List<String> getTargets() {\n        return targets;\n    }\n\n    public void setTargets(List<String> targets) {\n        this.targets = targets;\n    }\n\n    public long getMessageId() {\n        return messageId;\n    }\n\n    public void setMessageId(long messageId) {\n        this.messageId = messageId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/RobotCallbackPojo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class RobotCallbackPojo {\n    private String url;\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/SendChannelMessageData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SendChannelMessageData {\n    private List<String> targets;\n    private int line;\n    private MessagePayload payload;\n\n    public List<String> getTargets() {\n        return targets;\n    }\n\n    public void setTargets(List<String> targets) {\n        this.targets = targets;\n    }\n\n    public int getLine() {\n        return line;\n    }\n\n    public void setLine(int line) {\n        this.line = line;\n    }\n\n    public MessagePayload getPayload() {\n        return payload;\n    }\n\n    public void setPayload(MessagePayload payload) {\n        this.payload = payload;\n    }\n\n    public static boolean isValide(SendChannelMessageData sendMessageData) {\n        if(sendMessageData == null ||\n            sendMessageData.getPayload() == null) {\n            return false;\n        }\n        return true;\n    }\n\n    public WFCMessage.Message toProtoMessage(String channelId, String channelOwner) {\n        if (targets == null) {\n            targets = new ArrayList<>();\n        }\n\n        return WFCMessage.Message.newBuilder().setFromUser(channelOwner)\n            .setConversation(WFCMessage.Conversation.newBuilder().setType(ProtoConstants.ConversationType.ConversationType_Channel).setTarget(channelId).setLine(line))\n            .addAllTo(targets)\n            .setContent(payload.toProtoMessageContent())\n            .build();\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/SendMessageData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\nimport java.util.List;\n\npublic class SendMessageData {\n    private String sender;\n    private Conversation conv;\n    private MessagePayload payload;\n    private List<String> toUsers;\n    private boolean isMeshMessage;\n    private boolean isUserMessage;\n\n    public String getSender() {\n        return sender;\n    }\n\n    public void setSender(String sender) {\n        this.sender = sender;\n    }\n\n    public Conversation getConv() {\n        return conv;\n    }\n\n    public void setConv(Conversation conv) {\n        this.conv = conv;\n    }\n\n    public MessagePayload getPayload() {\n        return payload;\n    }\n\n    public void setPayload(MessagePayload payload) {\n        this.payload = payload;\n    }\n\n    public List<String> getToUsers() {\n        return toUsers;\n    }\n\n    public void setToUsers(List<String> toUsers) {\n        this.toUsers = toUsers;\n    }\n\n    public boolean isMeshMessage() {\n        return isMeshMessage;\n    }\n\n    public void setMeshMessage(boolean meshMessage) {\n        isMeshMessage = meshMessage;\n    }\n\n    public boolean isUserMessage() {\n        return isUserMessage;\n    }\n\n    public void setUserMessage(boolean userMessage) {\n        isUserMessage = userMessage;\n    }\n\n    public static boolean isValide(SendMessageData sendMessageData) {\n        if(sendMessageData == null ||\n            sendMessageData.getConv() == null ||\n            sendMessageData.getConv().getType() < 0 ||\n            sendMessageData.getConv().getType() > 6 ||\n            StringUtil.isNullOrEmpty(sendMessageData.getConv().getTarget()) ||\n            StringUtil.isNullOrEmpty(sendMessageData.getSender()) ||\n            sendMessageData.getPayload() == null) {\n            return false;\n        }\n        return true;\n    }\n\n    public WFCMessage.Message toProtoMessage() {\n        if (toUsers != null && toUsers.size() > 0) {\n            return WFCMessage.Message.newBuilder().setFromUser(sender)\n                .setConversation(WFCMessage.Conversation.newBuilder().setType(conv.getType()).setTarget(conv.getTarget()).setLine(conv.getLine()))\n                .setContent(payload.toProtoMessageContent())\n                .addAllTo(toUsers)\n                .build();\n        } else {\n            return WFCMessage.Message.newBuilder().setFromUser(sender)\n                .setConversation(WFCMessage.Conversation.newBuilder().setType(conv.getType()).setTarget(conv.getTarget()).setLine(conv.getLine()))\n                .setContent(payload.toProtoMessageContent())\n                .build();\n        }\n    }\n\n    public static SendMessageData fromProtoMessage(WFCMessage.Message protoMessage) {\n        SendMessageData data = new SendMessageData();\n        data.sender = protoMessage.getFromUser();\n        data.conv = new Conversation();\n        data.conv.setTarget(protoMessage.getConversation().getTarget());\n        data.conv.setType(protoMessage.getConversation().getType());\n        data.conv.setLine(protoMessage.getConversation().getLine());\n        data.payload = MessagePayload.fromProtoMessageContent(protoMessage.getContent());\n\n        return data;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/SendMessageResult.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\n/**\n * 发送消息结果类\n * <p>\n * 封装发送消息后的返回结果，包含消息UID和时间戳。\n * </p>\n */\npublic class SendMessageResult {\n    private long messageUid;\n    private long timestamp;\n\n    public SendMessageResult() {\n    }\n\n    public SendMessageResult(long messageUid, long timestamp) {\n        this.messageUid = messageUid;\n        this.timestamp = timestamp;\n    }\n\n    public long getMessageUid() {\n        return messageUid;\n    }\n\n    public void setMessageUid(long messageUid) {\n        this.messageUid = messageUid;\n    }\n\n    public long getTimestamp() {\n        return timestamp;\n    }\n\n    public void setTimestamp(long timestamp) {\n        this.timestamp = timestamp;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/StringPairPojo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class StringPairPojo {\n    private String first;\n    private String second;\n\n    public StringPairPojo() {\n    }\n\n    public StringPairPojo(String first, String second) {\n        this.first = first;\n        this.second = second;\n    }\n\n    public String getFirst() {\n        return first;\n    }\n\n    public void setFirst(String first) {\n        this.first = first;\n    }\n\n    public String getSecond() {\n        return second;\n    }\n\n    public void setSecond(String second) {\n        this.second = second;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/SystemSettingPojo.java",
    "content": "package cn.wildfirechat.pojos;\n\npublic class SystemSettingPojo {\n    public int id;\n    public String value;\n    public String desc;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/UpdateMessageContentData.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\npublic class UpdateMessageContentData {\n    private String operator;\n    private long messageUid;\n    private MessagePayload payload;\n    private int distribute;\n    private int updateTimestamp;\n    private int meshLocal;\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public long getMessageUid() {\n        return messageUid;\n    }\n\n    public void setMessageUid(long messageUid) {\n        this.messageUid = messageUid;\n    }\n\n    public MessagePayload getPayload() {\n        return payload;\n    }\n\n    public void setPayload(MessagePayload payload) {\n        this.payload = payload;\n    }\n\n    public int getDistribute() {\n        return distribute;\n    }\n\n    public void setDistribute(int distribute) {\n        this.distribute = distribute;\n    }\n\n    public int getUpdateTimestamp() {\n        return updateTimestamp;\n    }\n\n    public void setUpdateTimestamp(int updateTimestamp) {\n        this.updateTimestamp = updateTimestamp;\n    }\n\n    public int getMeshLocal() {\n        return meshLocal;\n    }\n\n    public void setMeshLocal(int meshLocal) {\n        this.meshLocal = meshLocal;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/UserOnlineStatus.java",
    "content": "package cn.wildfirechat.pojos;\n\nimport java.util.List;\n\npublic class UserOnlineStatus {\n    public static final int ONLINE = 0;\n    public static final int OFFLINE = 1;\n    public static final int LOGOUT = -1;\n\n    public String userId;\n    public String clientId;\n    public int platform;\n    public int status;\n    public long timestamp;\n    public String packageName;\n    public int customState;\n    public String customText;\n    public List<OutputCheckUserOnline.Session> sessions;\n\n    public UserOnlineStatus() {\n    }\n\n    public UserOnlineStatus(String userId, String clientId, int platform, int status, String packageName) {\n        this.userId = userId;\n        this.clientId = clientId;\n        this.platform = platform;\n        this.status = status;\n        this.packageName = packageName;\n        this.timestamp = System.currentTimeMillis();\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/UserSettingPojo.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos;\n\nimport cn.wildfirechat.proto.WFCMessage;\nimport io.netty.util.internal.StringUtil;\n\npublic class UserSettingPojo {\n    private String userId;\n    private int scope;\n    private String key;\n    private String value;\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public int getScope() {\n        return scope;\n    }\n\n    public void setScope(int scope) {\n        this.scope = scope;\n    }\n\n    public String getKey() {\n        return key;\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public String getValue() {\n        return value;\n    }\n\n    public void setValue(String value) {\n        this.value = value;\n    }\n    public WFCMessage.ModifyUserSettingReq toProtoRequest() {\n        WFCMessage.ModifyUserSettingReq.Builder builder = WFCMessage.ModifyUserSettingReq.newBuilder();\n        builder.setScope(scope);\n        if (!StringUtil.isNullOrEmpty(key))\n            builder.setKey(key);\n        if(!StringUtil.isNullOrEmpty(value))\n            builder.setValue(value);\n\n        return builder.build();\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/MeshRestResult.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\nimport com.google.gson.Gson;\n\npublic class MeshRestResult<T> {\n    private static Gson gson = new Gson();\n    public enum MeshRestCode {\n        SUCCESS(0, \"success\"),\n        ERROR_INVALID_MOBILE(1, \"无效的电话号码\"),\n        ERROR_SEND_SMS_OVER_FREQUENCY(3, \"请求验证码太频繁\"),\n        ERROR_SERVER_ERROR(4, \"服务器异常\"),\n        ERROR_CODE_EXPIRED(5, \"验证码已过期\"),\n        ERROR_CODE_INCORRECT(6, \"验证码或密码错误\"),\n        ERROR_SERVER_CONFIG_ERROR(7, \"服务器配置错误\"),\n        ERROR_SESSION_EXPIRED(8, \"会话不存在或已过期\"),\n        ERROR_SESSION_NOT_VERIFIED(9, \"会话没有验证\"),\n        ERROR_SESSION_NOT_SCANED(10, \"会话没有被扫码\"),\n        ERROR_SERVER_NOT_IMPLEMENT(11, \"功能没有实现\"),\n        ERROR_GROUP_ANNOUNCEMENT_NOT_EXIST(12, \"群公告不存在\"),\n        ERROR_NOT_LOGIN(13, \"没有登录\"),\n        ERROR_NO_RIGHT(14, \"没有权限\"),\n        ERROR_INVALID_PARAMETER(15, \"无效参数\"),\n        ERROR_NOT_EXIST(16, \"对象不存在\"),\n        ERROR_USER_NAME_ALREADY_EXIST(17, \"用户名已经存在\"),\n        ERROR_SESSION_CANCELED(18, \"会话已经取消\"),\n        ERROR_PASSWORD_INCORRECT(19, \"密码错误\"),\n        ERROR_FAILURE_TOO_MUCH_TIMES(20, \"密码错误次数太多，请等5分钟再试试\"),\n        ERROR_USER_FORBIDDEN(21, \"用户被封禁\");\n        public int code;\n        public String msg;\n\n        MeshRestCode(int code, String msg) {\n            this.code = code;\n            this.msg = msg;\n        }\n\n    }\n    private int remote_im_code;\n    private int remote_mesh_code;\n    private int local_mesh_code;\n    private String error_message;\n    private T result;\n\n    @Override\n    public String toString() {\n        return gson.toJson(this);\n    }\n\n    public static MeshRestResult ok() {\n        return new MeshRestResult();\n    }\n\n    public static MeshRestResult ok(Object object) {\n        return new MeshRestResult(object);\n    }\n\n    public static MeshRestResult remoteIMError(int code, String message) {\n        MeshRestResult r = new MeshRestResult();\n        r.remote_im_code = code;\n        r.error_message = message;\n        return r;\n    }\n\n    public static MeshRestResult remoteMeshError(int code, String message) {\n        MeshRestResult r = new MeshRestResult();\n        r.remote_mesh_code = code;\n        r.error_message = message;\n        return r;\n    }\n\n    public MeshRestResult addRemoteMeshError(int code, String message) {\n        MeshRestResult r = new MeshRestResult();\n        remote_mesh_code = code;\n        error_message = message;\n        return this;\n    }\n\n    public static MeshRestResult localMeshError(int code, String message) {\n        MeshRestResult r = new MeshRestResult();\n        r.local_mesh_code = code;\n        r.error_message = message;\n        return r;\n    }\n\n    public MeshRestResult addLocalMeshError(int code, String message) {\n        local_mesh_code = code;\n        error_message = message;\n        return this;\n    }\n\n\n    public MeshRestResult() {\n\n    }\n\n    public MeshRestResult(T object) {\n        result = object;\n    }\n\n    public T getResult() {\n        return result;\n    }\n\n    public void setResult(T result) {\n        this.result = result;\n    }\n\n    public int getRemote_im_code() {\n        return remote_im_code;\n    }\n\n    public void setRemote_im_code(int remote_im_code) {\n        this.remote_im_code = remote_im_code;\n    }\n\n    public int getRemote_mesh_code() {\n        return remote_mesh_code;\n    }\n\n    public void setRemote_mesh_code(int remote_mesh_code) {\n        this.remote_mesh_code = remote_mesh_code;\n    }\n\n    public int getLocal_mesh_code() {\n        return local_mesh_code;\n    }\n\n    public void setLocal_mesh_code(int local_mesh_code) {\n        this.local_mesh_code = local_mesh_code;\n    }\n\n    public String getError_message() {\n        return error_message;\n    }\n\n    public void setError_message(String error_message) {\n        this.error_message = error_message;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoAddFriendReq.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoAddFriendReq {\n    public String fromUserId;\n    public String reason;\n    public String targetUserId;\n    public String domainId;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoAddGroupMember.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\nimport cn.wildfirechat.pojos.PojoGroupMember;\n\nimport java.util.List;\n\npublic class PojoAddGroupMember {\n    public String domainId;\n    public String operator;\n    public String group_id;\n    public List<PojoGroupMember> members;\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public List<PojoGroupMember> getMembers() {\n        return members;\n    }\n\n    public void setMembers(List<PojoGroupMember> members) {\n        this.members = members;\n    }\n\n    public String getDomainId() {\n        return domainId;\n    }\n\n    public void setDomainId(String domainId) {\n        this.domainId = domainId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoAddJoinGroupRequest.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\nimport java.util.List;\n\npublic class PojoAddJoinGroupRequest {\n    public String domainId;\n    public String operator;\n    public String group_id;\n    public List<String> userIds;\n    public String reason;\n    public String extra;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoDeleteFriend.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoDeleteFriend {\n    public String domainId;\n    public String operator;\n    public String friendUid;\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public String getFriendUid() {\n        return friendUid;\n    }\n\n    public void setFriendUid(String friendUid) {\n        this.friendUid = friendUid;\n    }\n\n    public String getDomainId() {\n        return domainId;\n    }\n\n    public void setDomainId(String domainId) {\n        this.domainId = domainId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoDismissGroup.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoDismissGroup {\n    public String domainId;\n    public String operator;\n    public String group_id;\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public String getDomainId() {\n        return domainId;\n    }\n\n    public void setDomainId(String domainId) {\n        this.domainId = domainId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoDomainPingRequest.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos.mesh;\n\n\npublic class PojoDomainPingRequest {\n    public String domainId;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoDomainPingResponse.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.pojos.mesh;\n\n\npublic class PojoDomainPingResponse {\n    public boolean success;\n    public String errorMessage;\n    public String myDomainName;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoGroupUpdated.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\nimport cn.wildfirechat.pojos.PojoGroupInfo;\nimport cn.wildfirechat.pojos.PojoGroupMember;\n\nimport java.util.List;\n\npublic class PojoGroupUpdated {\n    public List<String> domainIds;\n    public PojoGroupInfo groupInfo;\n    public List<PojoGroupMember> members;\n\n    public List<String> getDomainIds() {\n        return domainIds;\n    }\n\n    public void setDomainIds(List<String> domainIds) {\n        this.domainIds = domainIds;\n    }\n\n    public PojoGroupInfo getGroupInfo() {\n        return groupInfo;\n    }\n\n    public void setGroupInfo(PojoGroupInfo groupInfo) {\n        this.groupInfo = groupInfo;\n    }\n\n    public List<PojoGroupMember> getMembers() {\n        return members;\n    }\n\n    public void setMembers(List<PojoGroupMember> members) {\n        this.members = members;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoHandleFriendRequestReq.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoHandleFriendRequestReq {\n    public String userId;\n    public int status;\n    public String targetUserId;\n    public String domainId;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoKickoffGroupMember.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\nimport java.util.List;\n\npublic class PojoKickoffGroupMember {\n    public String domainId;\n    public String operator;\n    public String group_id;\n    public List<String> members;\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public String getDomainId() {\n        return domainId;\n    }\n\n    public void setDomainId(String domainId) {\n        this.domainId = domainId;\n    }\n\n    public List<String> getMembers() {\n        return members;\n    }\n\n    public void setMembers(List<String> members) {\n        this.members = members;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoModifyGroupInfo.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoModifyGroupInfo {\n    public String domainId;\n    public String operator;\n    public String group_id;\n    public int type;\n    public String value;\n\n    public String getDomainId() {\n        return domainId;\n    }\n\n    public void setDomainId(String domainId) {\n        this.domainId = domainId;\n    }\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public String getValue() {\n        return value;\n    }\n\n    public void setValue(String value) {\n        this.value = value;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoPublishMessageReq.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\nimport cn.wildfirechat.pojos.SendMessageData;\n\nimport java.util.List;\n\npublic class PojoPublishMessageReq {\n    public SendMessageData messageData;\n    public List<String> receivers;\n    public String domainId;\n    public long messageId;\n    public boolean republish;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoQuitGroup.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoQuitGroup {\n    public String domainId;\n    public String operator;\n    public String group_id;\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n    \n    public String getDomainId() {\n        return domainId;\n    }\n\n    public void setDomainId(String domainId) {\n        this.domainId = domainId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoRecallMessageReq.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoRecallMessageReq {\n    public String domainId;\n    public long messageId;\n    public String operator;\n    public boolean isSenderRecall;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoSearchUserReq.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoSearchUserReq {\n    public String keyword;\n    public int searchType;\n    public int userType;\n    public int page;\n    public String domainId;\n\n    public String getKeyword() {\n        return keyword;\n    }\n\n    public void setKeyword(String keyword) {\n        this.keyword = keyword;\n    }\n\n    public int getSearchType() {\n        return searchType;\n    }\n\n    public void setSearchType(int searchType) {\n        this.searchType = searchType;\n    }\n\n    public int getUserType() {\n        return userType;\n    }\n\n    public void setUserType(int userType) {\n        this.userType = userType;\n    }\n\n    public int getPage() {\n        return page;\n    }\n\n    public void setPage(int page) {\n        this.page = page;\n    }\n\n    public String getDomainId() {\n        return domainId;\n    }\n\n    public void setDomainId(String domainId) {\n        this.domainId = domainId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoSearchUserRes.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\n\nimport java.util.List;\n\npublic class PojoSearchUserRes {\n    public List<InputOutputUserInfo> userInfos;\n    public String keyword;\n\n    public List<InputOutputUserInfo> getUserInfos() {\n        return userInfos;\n    }\n\n    public void setUserInfos(List<InputOutputUserInfo> userInfos) {\n        this.userInfos = userInfos;\n    }\n\n    public String getKeyword() {\n        return keyword;\n    }\n\n    public void setKeyword(String keyword) {\n        this.keyword = keyword;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoSendMessageReq.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\nimport cn.wildfirechat.pojos.SendMessageData;\n\npublic class PojoSendMessageReq {\n    public SendMessageData messageData;\n    public String clientId;\n    public String domainId;\n    public long messageId;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoString.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoString {\n    public String domainId;\n    public String string;\n\n    public String getString() {\n        return string;\n    }\n\n    public void setString(String string) {\n        this.string = string;\n    }\n\n    public String getDomainId() {\n        return domainId;\n    }\n\n    public void setDomainId(String domainId) {\n        this.domainId = domainId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoStringList.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\nimport java.util.List;\n\npublic class PojoStringList {\n    public String domainId;\n    public List<String> stringList;\n\n    public List<String> getStringList() {\n        return stringList;\n    }\n\n    public void setStringList(List<String> stringList) {\n        this.stringList = stringList;\n    }\n\n    public String getDomainId() {\n        return domainId;\n    }\n\n    public void setDomainId(String domainId) {\n        this.domainId = domainId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoTransferGroup.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoTransferGroup {\n    public String domainId;\n    public String operator;\n    public String newOwner;\n    public String group_id;\n\n    public String getOperator() {\n        return operator;\n    }\n\n    public void setOperator(String operator) {\n        this.operator = operator;\n    }\n\n    public String getGroup_id() {\n        return group_id;\n    }\n\n    public void setGroup_id(String group_id) {\n        this.group_id = group_id;\n    }\n\n    public String getNewOwner() {\n        return newOwner;\n    }\n\n    public void setNewOwner(String newOwner) {\n        this.newOwner = newOwner;\n    }\n\n    public String getDomainId() {\n        return domainId;\n    }\n\n    public void setDomainId(String domainId) {\n        this.domainId = domainId;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoUserConferenceEvent.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoUserConferenceEvent {\n    public String domainId;\n    public String data;\n    public String userId;\n    public String clientId;\n    public boolean isRobot;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoUserConferenceRequest.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoUserConferenceRequest {\n    public String domainId;\n    public String clientID;\n    public String fromUser;\n    public String request;\n    public long sessionId;\n    public String roomId;\n    public String data;\n    public boolean advanced;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/mesh/PojoUserConferenceResponse.java",
    "content": "package cn.wildfirechat.pojos.mesh;\n\npublic class PojoUserConferenceResponse {\n    public String data;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/CommentMsgPojo.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\n\nimport java.util.List;\n\npublic class CommentMsgPojo {\n    //commentId;\n    public long commentId;\n\n    //sender;\n    public String sender;\n\n    //timestamp\n    public long serverTime;\n\n    //feedId\n    public long feedId;\n\n    //type\n    public int type;\n\n    //content\n    public String text;\n\n    //to replyTo\n    public String replyTo;\n\n    //extra\n    public String extra;\n\n    public int ftype;\n\n    public String fcontent;\n\n    public String fsender;\n\n    public List<MediaEntry> fmedias;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/CommentPojo.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\npublic class CommentPojo {\n    //commentId;\n    public long commentId;\n\n    //replyId;\n    public long replyId;\n\n    //sender;\n    public String sender;\n\n    //timestamp\n    public long timestamp;\n\n    //feedId\n    public long feedId;\n\n    //type\n    public int type;\n\n    //content\n    public String text;\n\n    //to replyTo\n    public String replyTo;\n\n    //extra\n    public String extra;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/FeedPojo.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\n\nimport java.util.List;\n\npublic class FeedPojo {\n    //feedid\n    public long feedId;\n\n    //sender\n    public String sender;\n\n    //timestamp\n    public long timestamp;\n\n    //type\n    public int type;\n\n    //content\n    public String text;\n\n    //media urls\n    public List<MediaEntry> medias;\n\n    //to users\n    public List<String> to;\n\n    //excloud users\n    public List<String> ex;\n\n    //mentioned users\n    public List<String> mu;\n\n    //extra\n    public String extra;\n\n    public List<CommentPojo> comments;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/FeedsPojo.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\nimport java.util.List;\n\npublic class FeedsPojo {\n    public List<FeedPojo> feeds;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/IdPojo.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\npublic class IdPojo {\n    //feedid\n    public long id;\n\n    //feedid\n    public long id2;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/MediaEntry.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\npublic class MediaEntry {\n    public String m;\n    public String t;\n    public int w;\n    public int h;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/MomentProfilePojo.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class MomentProfilePojo {\n    public String bgUrl;\n    public List<String> blackList;\n    public List<String> blockList;\n    //stranger visiable count\n    public int svc;\n    public int visiableScope;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/PostFeedResult.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\npublic class PostFeedResult {\n    public long id;\n    public long timestamp;\n\n    public PostFeedResult(long id, long timestamp) {\n        this.id = id;\n        this.timestamp = timestamp;\n    }\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/PullCommentsRequestPojo.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\nimport java.util.List;\n\npublic class PullCommentsRequestPojo {\n    public static class IdPair {\n        public long fid;\n        public long cid;\n    }\n    public List<IdPair> ids;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/PullFeedRequestPojo.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\npublic class PullFeedRequestPojo {\n    //feedid\n    public long feedId;\n    public int count;\n    public String user;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/PullOneFeedRequestPojo.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\npublic class PullOneFeedRequestPojo {\n    public long feedId;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/PullProfileRequestPojo.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\npublic class PullProfileRequestPojo {\n    //userId\n    public String u;\n\n    //update date\n    public long d;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/PushProfileListRequestPojo.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\nimport java.util.List;\n\npublic class PushProfileListRequestPojo {\n    //block or black\n    public boolean b;\n\n    //add user list\n    public List<String> al;\n\n    //remove user list\n    public List<String> rl;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/pojos/moments/PushProfileValueRequestPojo.java",
    "content": "package cn.wildfirechat.pojos.moments;\n\npublic class PushProfileValueRequestPojo {\n    /*\n    WFMUpdateUserProfileType_BackgroudUrl,\n    WFMUpdateUserProfileType_StrangerVisiableCount,\n    WFMUpdateUserProfileType_VisiableScope\n     */\n    public int t;\n\n    //string value depends on t\n    public String v;\n\n    //int value depends on t\n    public int i;\n}\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/proto/ProtoConstants.java",
    "content": "package cn.wildfirechat.proto;\n\npublic class ProtoConstants {\n\n    //message Conversation -> type\n    public interface ConversationType {\n        int ConversationType_Private = 0;\n        int ConversationType_Group = 1;\n        int ConversationType_ChatRoom = 2;\n        int ConversationType_Channel = 3;\n        int ConversationType_Things = 4;\n        int ConversationType_SecretChat = 5;\n    }\n\n    //message GroupInfo -> type\n    public interface GroupType {\n        //member can add quit change group name and portrait, owner can do all the operations\n        int GroupType_Normal = 0;\n        //every member can add quit change group name and portrait, no one can kickoff others\n        int GroupType_Free = 1;\n        //member can only quit, owner can do all the operations\n        int GroupType_Restricted = 2;\n        //member can not do anything, server api manage the group\n        int GroupType_Organization = 3;\n    }\n\n    //message GroupMember -> type\n    public interface GroupMemberType {\n        int GroupMemberType_Normal = 0;\n        int GroupMemberType_Manager = 1;\n        int GroupMemberType_Owner = 2;\n        int GroupMemberType_Silent = 3;\n        int GroupMemberType_Removed = 4;\n        int GroupMemberType_Allowed = 5;\n    }\n\n    //message FriendRequest -> status\n    public interface FriendRequestStatus {\n        int RequestStatus_Sent = 0;\n        int RequestStatus_Accepted = 1;\n        int RequestStatus_Rejected = 2;\n    }\n\n    //message UploadDeviceTokenRequest -> platform\n    public interface Platform {\n        int Platform_UNSET = 0;\n        int Platform_iOS = 1;\n        int Platform_Android = 2;\n        int Platform_Windows = 3;\n        int Platform_OSX = 4;\n        int Platform_WEB = 5;\n        int Platform_WX = 6;\n        int Platform_LINUX = 7;\n        int Platform_iPad = 8;\n        int Platform_APad = 9;\n        int Platform_Harmony = 10;\n        int Platform_HarmonyPad = 11;\n        int Platform_HarmonyPC = 12;\n        // 穿戴端 (Wearable)\n        int Platform_AndroidWearable = 13;\n        int Platform_HarmonyWearable = 14;\n        // TV端\n        int Platform_AndroidTV = 15;\n        int Platform_AppleTV = 16;\n        int Platform_HarmonyTV = 17;\n        int Platform_MAX = Platform_HarmonyTV;\n    }\n\n    //message NotifyMessage & PullMessageRequest -> type\n    public interface PullType {\n        int Pull_Normal = 0;\n        int Pull_ChatRoom = 1;\n        int Pull_Group = 2;\n    }\n\n    //message UserResult -> code\n    public interface UserResultCode {\n        int Success = 0;\n        int NotFound = 1;\n        int NotModified = 2;\n    }\n\n    //message ChatroomInfo -> state\n    public interface ChatroomState {\n        int Chatroom_State_Normal = 0;\n        int Chatroom_State_NotStart = 1;\n        int Chatroom_State_End = 2;\n    }\n\n\n    //message MessageContent -> contentType\n    public interface ContentType {\n        int Unknown = 0;\n        int Text = 1;\n        int Voice = 2;\n        int Image = 3;\n        int Location = 4;\n        int File = 5;\n        int Video = 6;\n        int Sticker = 7;\n        int Link = 8;\n        int P_TEXT = 9;\n        int Name_Card = 10;\n        int Composited = 11;\n        int Rich_Notification = 12;\n        int Articles = 13;\n        int StreamingText_Generationg = 14;\n        int StreamingText_Generated = 15;\n        int Not_Delivered = 16;\n        int Ptt_Voice = 23;\n        int Enter_Channel_Chat = 71;\n        int Leave_Channel_Chat = 72;\n        int Recall = 80;\n        int Delete = 81;\n        int Tip = 90;\n        int Typing = 91;\n        int Friend_Greeting = 92;\n        int Friend_Added = 93;\n        int PC_Login_Request = 94;\n        int Create_Group = 104;\n        int Add_Group_Member = 105;\n        int Kickoff_Group_Member = 106;\n        int Quit_Group = 107;\n        int Dismiss_Group = 108;\n        int Transfer_Group_Owner = 109;\n        int Change_Group_Name = 110;;\n        int Modify_Group_Alias = 111;\n        int Change_Group_Portrait = 112;\n        int Change_Group_Mute = 113;\n        int Change_Group_JoinType = 114;\n        int Change_Group_PrivateChat = 115;\n        int Change_Group_Searchable = 116;\n        int Set_Group_Manager = 117;\n        int Mute_Group_Member = 118;\n        int Allow_Group_Member = 119;\n        int Kickoff_Group_Member_Visible_Notification = 120;\n        int Quit_Group_Visible_Notification = 121;\n        int Modify_Group_Extra = 122;\n        int Modify_Group_Member_Extra = 123;\n\n        int Call_Start = 400;\n        int Call_Accept = 401;\n        int Call_End = 402;\n        int Call_Add_Participant = 406;\n        int Call_Multi_Call_Ongoing = 416;\n    }\n\n    public interface MessagePersistFlag {\n        int NOT_PERSIST = 0;\n        int PERSIST = 1;\n        int PERSIST_AND_COUNT = 3;\n        int TRANSPARENT = 4;\n    }\n\n    public interface MessageMediaType {\n        int GENERAL = 0;\n        int IMAGE = 1;\n        int VOICE = 2;\n        int VIDEO = 3;\n        int FILE = 4;\n        int PORTRAIT = 5;\n        int FAVORITE = 6;\n        int STICKER = 7;\n        int MOMENTS = 8;\n    }\n\n    //ModifyGroupInfoRequest -> type\n    public interface ModifyGroupInfoType {\n        int Modify_Group_Name = 0;\n        int Modify_Group_Portrait = 1;\n        int Modify_Group_Extra = 2;\n        int Modify_Group_Mute = 3;\n        int Modify_Group_JoinType = 4;\n        int Modify_Group_PrivateChat = 5;\n        int Modify_Group_Searchable = 6;\n        //仅专业版支持\n        int Modify_Group_History_Message = 7;\n        //仅专业版的server api支持\n        int Modify_Group_Max_Member_Count = 8;\n        //仅专业版的server api支持\n        int Modify_Group_Super_Group = 9;\n        int Modify_Group_Type = 10;\n    }\n\n    //ModifyGroupInfoRequest -> type\n    public interface PersistFlag {\n        int Not_Persist = 0;\n        int Persist = 1;\n        int Persist_And_Count = 3;\n        int Transparent = 4;\n    }\n\n\n    //ModifyChannelInfoRequest -> type\n    public interface ModifyChannelInfoType {\n        int Modify_Channel_Name = 0;\n        int Modify_Channel_Portrait = 1;\n        int Modify_Channel_Desc = 2;\n        int Modify_Channel_Extra = 3;\n        int Modify_Channel_Secret = 4;\n        int Modify_Channel_Callback = 5;\n        int Modify_Channel_OnlyCallback = 6;\n        int Modify_Channel_Menu = 7;\n    }\n\n    //Channel -> status\n    //第0位表示是否允许查看用户所有信息，还是只允许看用户id，用户名称，用户昵称和用户头像\n    //第1位表示是否允许查看非订阅用户信息\n    //第2位表示是否允许主动添加用户订阅关系\n    //第3位表示是否允许给非订阅用户发送消息\n    //第4位表示是否私有，不可以被用户搜索和主动订阅\n    //第6位表示是否删除\n    //第8位表示是否是全局频道，全局频道没有订阅关系，会发送给系统内所有成员。可以给非订阅用户单独发消息。\n    public interface ChannelState {\n        int Channel_State_Mask_FullInfo = 0x01;\n        int Channel_State_Mask_Unsubscribed_User_Access = 0x02;\n        int Channel_State_Mask_Active_Subscribe = 0x04;\n        int Channel_State_Mask_Message_Unsubscribed = 0x08;\n        int Channel_State_Mask_Private = 0x10;\n        int Channel_State_Mask_Deleted = 0x40;\n        int Channel_State_Mask_Global = 0x80;\n    }\n\n\n    public interface UserType {\n        int UserType_Normal = 0;\n        int UserType_Robot = 1;\n        int UserType_Device = 2;\n        int UserType_Admin = 3;\n        int UserType_Super_Admin = 100;\n    }\n\n\n    public interface SystemSettingType {\n        int Group_Max_Member_Count = 1;\n        int NOT_ALLOW_USER_NAMES = 2;\n    }\n\n    public interface SearchUserType {\n        int SearchUserType_General = 0;\n        int SearchUserType_Name_Mobile = 1;\n        int SearchUserType_Name = 2;\n        int SearchUserType_Mobile = 3;\n        int SearchUserType_UserId = 4;\n        int SearchUserType_Name_Mobile_UserId = 5;\n        int SearchUserType_Name_Mobile_DisplayName = 100;\n    }\n\n    public interface UserSearchUserType {\n        int UserSearchUserType_ALL = 0;\n        int UserSearchUserType_ONLY_USER = 1;\n        int UserSearchUserType_ONLY_ROBOT = 2;\n    }\n\n    public interface DisableSearchMask {\n        int DisableSearchDisplayNameMask = 1;\n        int DisableSearchNameMask = 2;\n        int DisableSearchMobileMask = 4;\n        int DisableSearchUserIdMask = 8;\n    }\n\n    public interface UserStatus {\n        int Normal = 0;\n        int Muted = 1;\n        int Forbidden = 2;\n    }\n\n    public interface BlacklistStrategy {\n        int Message_Reject = 0;\n        int Message_Ignore = 1;\n    }\n\n    public interface GroupUpdateEventType {\n        int Group_Event_Create = 0;\n        int Group_Event_Update = 1;\n        int Group_Event_Transfer = 2;\n        int Group_Event_Mute = 3;\n        int Group_Event_Unmute = 4;\n        int Group_Event_Destroy = 5;\n    }\n\n    public interface GroupMemberUpdateEventType {\n        int Group_Member_Event_Join = 0;\n        int Group_Member_Event_Leave = 1;\n        int Group_Member_Event_Kickoff = 2;\n        int Group_Member_Event_Type_Update = 3;\n        int Group_Member_Event_Alias = 4;\n        int Group_Member_Event_Extra = 5;\n    }\n\n    public interface ChannelUpdateEventType {\n        int Channel_Event_Create = 0;\n        int Channel_Event_Update = 1;\n        int Channel_Event_Transfer = 2;\n        int Channel_Event_Destroy = 3;\n    }\n\n    public interface ChatroomUpdateEventType {\n        int Chatroom_Event_Create = 0;\n        int Chatroom_Event_Destroy = 1;\n    }\n\n    public interface ChatroomMemberUpdateEventType {\n        int Chatroom_Member_Event_Join = 0;\n        int Chatroom_Member_Event_Leave = 1;\n        int Chatroom_Member_Event_Kickoff = 2;\n        int Chatroom_Member_Event_Mute = 3;\n        int Chatroom_Member_Event_Unmute = 4;\n    }\n\n    public interface UpdateUserInfoMask {\n        int Update_User_DisplayName = 0x01;\n        int Update_User_Portrait = 0x02;\n        int Update_User_Gender = 0x04;\n        int Update_User_Mobile = 0x08;\n        int Update_User_Email = 0x10;\n        int Update_User_Address = 0x20;\n        int Update_User_Company = 0x40;\n        int Update_User_Social = 0x80;\n        int Update_User_Extra = 0x100;\n        int Update_User_Name = 0x200;\n    }\n\n    public enum RequestSourceType {\n        Request_From_User,\n        Request_From_Admin,\n        Request_From_Robot,\n        Request_From_Channel;\n    }\n\n    public interface ApplicationType {\n        int ApplicationType_Robot = 0;\n        int ApplicationType_Channel = 1;\n        int ApplicationType_Admin = 2;\n    }\n\n    //禁止客户端群操作。\n    // 第1位是禁止创建群组，\n    // 第2位是禁止销毁群组，\n    // 3位禁止加入群，\n    // 4位禁止退出群，\n    // 5位禁止邀请群成员，\n    // 6位禁止移出群成员，\n    // 7位禁止转移群\n    // 8位禁止设置群管理员\n    // 9位禁止允许群成员(专业版支持），\n    // 10位禁止群禁言\n    // 11位禁止修改群组信息，\n    // 12位禁止群成员禁言(专业版支持)\n    public interface ForbiddenClientGroupOperationMask {\n        int Forbidden_Create_Group = 0x01;\n        int Forbidden_Dismiss_Group = 0x02;\n        int Forbidden_Join_Group = 0x04;\n        int Forbidden_Quit_Group = 0x08;\n        int Forbidden_Invite_Group_Member = 0x10;\n        int Forbidden_Kickoff_Group_Member = 0x20;\n        int Forbidden_Transfer_Group = 0x40;\n        int Forbidden_Set_Group_Manage = 0x80;\n        int Forbidden_Allow_Group_Member = 0x100;\n        int Forbidden_Mute_Group = 0x200;\n        int Forbidden_Modify_Group_Info = 0x400;\n        int Forbidden_Mute_Group_Member = 0x800;\n    }\n\n    public interface MomentsContentType {\n        int Moments_Content_Text_Type = 0;\n        int Moments_Content_Image_Type = 1;\n        int Moments_Content_Video_Type = 2;\n        int Moments_Content_Link_Type = 3;\n    }\n\n    public interface MomentsCommentType {\n        int Moments_Comment_Text_Type = 0;\n        int Moments_Comment_Thumbup_Type = 1;\n    }\n\n    public interface MomentsVisibleScope {\n        int Moments_VisibleScope_NoLimit = 0;\n        int Moments_VisibleScope_3Days = 1;\n        int Moments_VisibleScope_1Month = 2;\n        int Moments_VisibleScope_6Months = 3;\n    };\n\n    public static final int MESSAGE_CONTENT_TYPE_CREATE_GROUP = 104;\n    public static final int MESSAGE_CONTENT_TYPE_ADD_GROUP_MEMBER = 105;\n    public static final int MESSAGE_CONTENT_TYPE_KICKOF_GROUP_MEMBER = 106;\n    public static final int MESSAGE_CONTENT_TYPE_QUIT_GROUP = 107;\n    public static final int MESSAGE_CONTENT_TYPE_DISMISS_GROUP = 108;\n    public static final int MESSAGE_CONTENT_TYPE_TRANSFER_GROUP_OWNER = 109;\n    public static final int MESSAGE_CONTENT_TYPE_CHANGE_GROUP_NAME = 110;\n    public static final int MESSAGE_CONTENT_TYPE_MODIFY_GROUP_ALIAS = 111;\n    public static final int MESSAGE_CONTENT_TYPE_CHANGE_GROUP_PORTRAIT = 112;\n\n    public static final int MESSAGE_CONTENT_TYPE_CHANGE_MUTE = 113;\n    public static final int MESSAGE_CONTENT_TYPE_CHANGE_JOINTYPE = 114;\n    public static final int MESSAGE_CONTENT_TYPE_CHANGE_PRIVATECHAT = 115;\n    public static final int MESSAGE_CONTENT_TYPE_CHANGE_SEARCHABLE = 116;\n\n    public static final int MESSAGE_CONTENT_TYPE_SET_MANAGER = 117;\n    public static final int MESSAGE_CONTENT_TYPE_MUTE_MEMBER = 118;\n    public static final int MESSAGE_CONTENT_TYPE_ALLOW_MEMBER = 119;\n    public static final int MESSAGE_CONTENT_TYPE_KICKOF_GROUP_MEMBER_VISIBLE = 120;\n    public static final int MESSAGE_CONTENT_TYPE_QUIT_GROUP_VISIBLE = 121;\n    \n    public static final int MESSAGE_CONTENT_TYPE_MODIFY_GROUP_EXTRA = 122;\n    public static final int MESSAGE_CONTENT_TYPE_MODIFY_GROUP_MEMBER_EXTRA = 123;\n    public static final int MESSAGE_CONTENT_TYPE_MODIFY_GROUP_SETTINGS = 124;\n    public static final int MESSAGE_CONTENT_TYPE_REJECT_JOIN_GROUP = 125;\n}\n\n"
  },
  {
    "path": "common/src/main/java/cn/wildfirechat/proto/WFCMessage.java",
    "content": "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n// source: wfcmessage_community.proto\n\npackage cn.wildfirechat.proto;\n\npublic final class WFCMessage {\n  private WFCMessage() {}\n  public static void registerAllExtensions(\n      com.google.protobuf.ExtensionRegistry registry) {\n  }\n  public interface AddFriendRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string target_uid = 1;\n    /**\n     * <code>required string target_uid = 1;</code>\n     */\n    boolean hasTargetUid();\n    /**\n     * <code>required string target_uid = 1;</code>\n     */\n    java.lang.String getTargetUid();\n    /**\n     * <code>required string target_uid = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getTargetUidBytes();\n\n    // required string reason = 2;\n    /**\n     * <code>required string reason = 2;</code>\n     */\n    boolean hasReason();\n    /**\n     * <code>required string reason = 2;</code>\n     */\n    java.lang.String getReason();\n    /**\n     * <code>required string reason = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getReasonBytes();\n\n    // optional string extra = 3;\n    /**\n     * <code>optional string extra = 3;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 3;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n  }\n  /**\n   * Protobuf type {@code AddFriendRequest}\n   */\n  public static final class AddFriendRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements AddFriendRequestOrBuilder {\n    // Use AddFriendRequest.newBuilder() to construct.\n    private AddFriendRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private AddFriendRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final AddFriendRequest defaultInstance;\n    public static AddFriendRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public AddFriendRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private AddFriendRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              targetUid_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              reason_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              extra_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_AddFriendRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_AddFriendRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.AddFriendRequest.class, cn.wildfirechat.proto.WFCMessage.AddFriendRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<AddFriendRequest> PARSER =\n        new com.google.protobuf.AbstractParser<AddFriendRequest>() {\n      public AddFriendRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new AddFriendRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<AddFriendRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string target_uid = 1;\n    public static final int TARGET_UID_FIELD_NUMBER = 1;\n    private java.lang.Object targetUid_;\n    /**\n     * <code>required string target_uid = 1;</code>\n     */\n    public boolean hasTargetUid() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string target_uid = 1;</code>\n     */\n    public java.lang.String getTargetUid() {\n      java.lang.Object ref = targetUid_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          targetUid_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string target_uid = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTargetUidBytes() {\n      java.lang.Object ref = targetUid_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        targetUid_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string reason = 2;\n    public static final int REASON_FIELD_NUMBER = 2;\n    private java.lang.Object reason_;\n    /**\n     * <code>required string reason = 2;</code>\n     */\n    public boolean hasReason() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string reason = 2;</code>\n     */\n    public java.lang.String getReason() {\n      java.lang.Object ref = reason_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          reason_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string reason = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getReasonBytes() {\n      java.lang.Object ref = reason_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        reason_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string extra = 3;\n    public static final int EXTRA_FIELD_NUMBER = 3;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 3;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string extra = 3;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      targetUid_ = \"\";\n      reason_ = \"\";\n      extra_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasTargetUid()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasReason()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getTargetUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getReasonBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getExtraBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getTargetUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getReasonBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getExtraBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.AddFriendRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddFriendRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddFriendRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddFriendRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddFriendRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddFriendRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddFriendRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddFriendRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddFriendRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddFriendRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.AddFriendRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code AddFriendRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.AddFriendRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_AddFriendRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_AddFriendRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.AddFriendRequest.class, cn.wildfirechat.proto.WFCMessage.AddFriendRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.AddFriendRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        targetUid_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        reason_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_AddFriendRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.AddFriendRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.AddFriendRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.AddFriendRequest build() {\n        cn.wildfirechat.proto.WFCMessage.AddFriendRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.AddFriendRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.AddFriendRequest result = new cn.wildfirechat.proto.WFCMessage.AddFriendRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.targetUid_ = targetUid_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.reason_ = reason_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.extra_ = extra_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.AddFriendRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.AddFriendRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.AddFriendRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.AddFriendRequest.getDefaultInstance()) return this;\n        if (other.hasTargetUid()) {\n          bitField0_ |= 0x00000001;\n          targetUid_ = other.targetUid_;\n          onChanged();\n        }\n        if (other.hasReason()) {\n          bitField0_ |= 0x00000002;\n          reason_ = other.reason_;\n          onChanged();\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000004;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasTargetUid()) {\n          \n          return false;\n        }\n        if (!hasReason()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.AddFriendRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.AddFriendRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string target_uid = 1;\n      private java.lang.Object targetUid_ = \"\";\n      /**\n       * <code>required string target_uid = 1;</code>\n       */\n      public boolean hasTargetUid() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string target_uid = 1;</code>\n       */\n      public java.lang.String getTargetUid() {\n        java.lang.Object ref = targetUid_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          targetUid_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string target_uid = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTargetUidBytes() {\n        java.lang.Object ref = targetUid_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          targetUid_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string target_uid = 1;</code>\n       */\n      public Builder setTargetUid(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        targetUid_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string target_uid = 1;</code>\n       */\n      public Builder clearTargetUid() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        targetUid_ = getDefaultInstance().getTargetUid();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string target_uid = 1;</code>\n       */\n      public Builder setTargetUidBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        targetUid_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string reason = 2;\n      private java.lang.Object reason_ = \"\";\n      /**\n       * <code>required string reason = 2;</code>\n       */\n      public boolean hasReason() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string reason = 2;</code>\n       */\n      public java.lang.String getReason() {\n        java.lang.Object ref = reason_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          reason_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string reason = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getReasonBytes() {\n        java.lang.Object ref = reason_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          reason_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string reason = 2;</code>\n       */\n      public Builder setReason(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        reason_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string reason = 2;</code>\n       */\n      public Builder clearReason() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        reason_ = getDefaultInstance().getReason();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string reason = 2;</code>\n       */\n      public Builder setReasonBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        reason_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string extra = 3;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 3;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional string extra = 3;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 3;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 3;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 3;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:AddFriendRequest)\n    }\n\n    static {\n      defaultInstance = new AddFriendRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:AddFriendRequest)\n  }\n\n  public interface ConversationOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int32 type = 1;\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    int getType();\n\n    // required string target = 2;\n    /**\n     * <code>required string target = 2;</code>\n     */\n    boolean hasTarget();\n    /**\n     * <code>required string target = 2;</code>\n     */\n    java.lang.String getTarget();\n    /**\n     * <code>required string target = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getTargetBytes();\n\n    // required int32 line = 3;\n    /**\n     * <code>required int32 line = 3;</code>\n     */\n    boolean hasLine();\n    /**\n     * <code>required int32 line = 3;</code>\n     */\n    int getLine();\n  }\n  /**\n   * Protobuf type {@code Conversation}\n   */\n  public static final class Conversation extends\n      com.google.protobuf.GeneratedMessage\n      implements ConversationOrBuilder {\n    // Use Conversation.newBuilder() to construct.\n    private Conversation(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private Conversation(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final Conversation defaultInstance;\n    public static Conversation getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public Conversation getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Conversation(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              type_ = input.readInt32();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              target_ = input.readBytes();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              line_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_Conversation_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_Conversation_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.Conversation.class, cn.wildfirechat.proto.WFCMessage.Conversation.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<Conversation> PARSER =\n        new com.google.protobuf.AbstractParser<Conversation>() {\n      public Conversation parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Conversation(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Conversation> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int32 type = 1;\n    public static final int TYPE_FIELD_NUMBER = 1;\n    private int type_;\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    // required string target = 2;\n    public static final int TARGET_FIELD_NUMBER = 2;\n    private java.lang.Object target_;\n    /**\n     * <code>required string target = 2;</code>\n     */\n    public boolean hasTarget() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string target = 2;</code>\n     */\n    public java.lang.String getTarget() {\n      java.lang.Object ref = target_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          target_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string target = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTargetBytes() {\n      java.lang.Object ref = target_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        target_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 line = 3;\n    public static final int LINE_FIELD_NUMBER = 3;\n    private int line_;\n    /**\n     * <code>required int32 line = 3;</code>\n     */\n    public boolean hasLine() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required int32 line = 3;</code>\n     */\n    public int getLine() {\n      return line_;\n    }\n\n    private void initFields() {\n      type_ = 0;\n      target_ = \"\";\n      line_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasTarget()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasLine()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, type_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getTargetBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt32(3, line_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, type_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getTargetBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(3, line_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.Conversation parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Conversation parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Conversation parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Conversation parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Conversation parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Conversation parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Conversation parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Conversation parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Conversation parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Conversation parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.Conversation prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code Conversation}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Conversation_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Conversation_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.Conversation.class, cn.wildfirechat.proto.WFCMessage.Conversation.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.Conversation.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        target_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        line_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Conversation_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Conversation getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.Conversation.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Conversation build() {\n        cn.wildfirechat.proto.WFCMessage.Conversation result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Conversation buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.Conversation result = new cn.wildfirechat.proto.WFCMessage.Conversation(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.type_ = type_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.target_ = target_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.line_ = line_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.Conversation) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.Conversation)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.Conversation other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.Conversation.getDefaultInstance()) return this;\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        if (other.hasTarget()) {\n          bitField0_ |= 0x00000002;\n          target_ = other.target_;\n          onChanged();\n        }\n        if (other.hasLine()) {\n          setLine(other.getLine());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasType()) {\n          \n          return false;\n        }\n        if (!hasTarget()) {\n          \n          return false;\n        }\n        if (!hasLine()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.Conversation parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.Conversation) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int32 type = 1;\n      private int type_ ;\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00000001;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required string target = 2;\n      private java.lang.Object target_ = \"\";\n      /**\n       * <code>required string target = 2;</code>\n       */\n      public boolean hasTarget() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string target = 2;</code>\n       */\n      public java.lang.String getTarget() {\n        java.lang.Object ref = target_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          target_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string target = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTargetBytes() {\n        java.lang.Object ref = target_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          target_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string target = 2;</code>\n       */\n      public Builder setTarget(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        target_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string target = 2;</code>\n       */\n      public Builder clearTarget() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        target_ = getDefaultInstance().getTarget();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string target = 2;</code>\n       */\n      public Builder setTargetBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        target_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 line = 3;\n      private int line_ ;\n      /**\n       * <code>required int32 line = 3;</code>\n       */\n      public boolean hasLine() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required int32 line = 3;</code>\n       */\n      public int getLine() {\n        return line_;\n      }\n      /**\n       * <code>required int32 line = 3;</code>\n       */\n      public Builder setLine(int value) {\n        bitField0_ |= 0x00000004;\n        line_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 line = 3;</code>\n       */\n      public Builder clearLine() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        line_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:Conversation)\n    }\n\n    static {\n      defaultInstance = new Conversation(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:Conversation)\n  }\n\n  public interface GroupInfoOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // optional string target_id = 1;\n    /**\n     * <code>optional string target_id = 1;</code>\n     */\n    boolean hasTargetId();\n    /**\n     * <code>optional string target_id = 1;</code>\n     */\n    java.lang.String getTargetId();\n    /**\n     * <code>optional string target_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getTargetIdBytes();\n\n    // required string name = 2;\n    /**\n     * <code>required string name = 2;</code>\n     */\n    boolean hasName();\n    /**\n     * <code>required string name = 2;</code>\n     */\n    java.lang.String getName();\n    /**\n     * <code>required string name = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getNameBytes();\n\n    // optional string portrait = 3;\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    boolean hasPortrait();\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    java.lang.String getPortrait();\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getPortraitBytes();\n\n    // optional string owner = 4;\n    /**\n     * <code>optional string owner = 4;</code>\n     */\n    boolean hasOwner();\n    /**\n     * <code>optional string owner = 4;</code>\n     */\n    java.lang.String getOwner();\n    /**\n     * <code>optional string owner = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getOwnerBytes();\n\n    // required int32 type = 5;\n    /**\n     * <code>required int32 type = 5;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>required int32 type = 5;</code>\n     */\n    int getType();\n\n    // optional int32 member_count = 6;\n    /**\n     * <code>optional int32 member_count = 6;</code>\n     */\n    boolean hasMemberCount();\n    /**\n     * <code>optional int32 member_count = 6;</code>\n     */\n    int getMemberCount();\n\n    // optional string extra = 7;\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n\n    // optional int64 update_dt = 8;\n    /**\n     * <code>optional int64 update_dt = 8;</code>\n     */\n    boolean hasUpdateDt();\n    /**\n     * <code>optional int64 update_dt = 8;</code>\n     */\n    long getUpdateDt();\n\n    // optional int64 member_update_dt = 9;\n    /**\n     * <code>optional int64 member_update_dt = 9;</code>\n     */\n    boolean hasMemberUpdateDt();\n    /**\n     * <code>optional int64 member_update_dt = 9;</code>\n     */\n    long getMemberUpdateDt();\n\n    // optional int32 mute = 10;\n    /**\n     * <code>optional int32 mute = 10;</code>\n     */\n    boolean hasMute();\n    /**\n     * <code>optional int32 mute = 10;</code>\n     */\n    int getMute();\n\n    // optional int32 join_type = 11;\n    /**\n     * <code>optional int32 join_type = 11;</code>\n     */\n    boolean hasJoinType();\n    /**\n     * <code>optional int32 join_type = 11;</code>\n     */\n    int getJoinType();\n\n    // optional int32 private_chat = 12;\n    /**\n     * <code>optional int32 private_chat = 12;</code>\n     */\n    boolean hasPrivateChat();\n    /**\n     * <code>optional int32 private_chat = 12;</code>\n     */\n    int getPrivateChat();\n\n    // optional int32 searchable = 13;\n    /**\n     * <code>optional int32 searchable = 13;</code>\n     */\n    boolean hasSearchable();\n    /**\n     * <code>optional int32 searchable = 13;</code>\n     */\n    int getSearchable();\n\n    // optional int32 max_member_count = 14;\n    /**\n     * <code>optional int32 max_member_count = 14;</code>\n     */\n    boolean hasMaxMemberCount();\n    /**\n     * <code>optional int32 max_member_count = 14;</code>\n     */\n    int getMaxMemberCount();\n\n    // optional int32 history_message = 15;\n    /**\n     * <code>optional int32 history_message = 15;</code>\n     */\n    boolean hasHistoryMessage();\n    /**\n     * <code>optional int32 history_message = 15;</code>\n     */\n    int getHistoryMessage();\n\n    // optional int32 super_group = 16;\n    /**\n     * <code>optional int32 super_group = 16;</code>\n     */\n    boolean hasSuperGroup();\n    /**\n     * <code>optional int32 super_group = 16;</code>\n     */\n    int getSuperGroup();\n\n    // optional int32 deleted = 17;\n    /**\n     * <code>optional int32 deleted = 17;</code>\n     */\n    boolean hasDeleted();\n    /**\n     * <code>optional int32 deleted = 17;</code>\n     */\n    int getDeleted();\n  }\n  /**\n   * Protobuf type {@code GroupInfo}\n   */\n  public static final class GroupInfo extends\n      com.google.protobuf.GeneratedMessage\n      implements GroupInfoOrBuilder {\n    // Use GroupInfo.newBuilder() to construct.\n    private GroupInfo(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private GroupInfo(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final GroupInfo defaultInstance;\n    public static GroupInfo getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public GroupInfo getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private GroupInfo(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              targetId_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              name_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              portrait_ = input.readBytes();\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000008;\n              owner_ = input.readBytes();\n              break;\n            }\n            case 40: {\n              bitField0_ |= 0x00000010;\n              type_ = input.readInt32();\n              break;\n            }\n            case 48: {\n              bitField0_ |= 0x00000020;\n              memberCount_ = input.readInt32();\n              break;\n            }\n            case 58: {\n              bitField0_ |= 0x00000040;\n              extra_ = input.readBytes();\n              break;\n            }\n            case 64: {\n              bitField0_ |= 0x00000080;\n              updateDt_ = input.readInt64();\n              break;\n            }\n            case 72: {\n              bitField0_ |= 0x00000100;\n              memberUpdateDt_ = input.readInt64();\n              break;\n            }\n            case 80: {\n              bitField0_ |= 0x00000200;\n              mute_ = input.readInt32();\n              break;\n            }\n            case 88: {\n              bitField0_ |= 0x00000400;\n              joinType_ = input.readInt32();\n              break;\n            }\n            case 96: {\n              bitField0_ |= 0x00000800;\n              privateChat_ = input.readInt32();\n              break;\n            }\n            case 104: {\n              bitField0_ |= 0x00001000;\n              searchable_ = input.readInt32();\n              break;\n            }\n            case 112: {\n              bitField0_ |= 0x00002000;\n              maxMemberCount_ = input.readInt32();\n              break;\n            }\n            case 120: {\n              bitField0_ |= 0x00004000;\n              historyMessage_ = input.readInt32();\n              break;\n            }\n            case 128: {\n              bitField0_ |= 0x00008000;\n              superGroup_ = input.readInt32();\n              break;\n            }\n            case 136: {\n              bitField0_ |= 0x00010000;\n              deleted_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GroupInfo_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GroupInfo_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.GroupInfo.class, cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<GroupInfo> PARSER =\n        new com.google.protobuf.AbstractParser<GroupInfo>() {\n      public GroupInfo parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new GroupInfo(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<GroupInfo> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // optional string target_id = 1;\n    public static final int TARGET_ID_FIELD_NUMBER = 1;\n    private java.lang.Object targetId_;\n    /**\n     * <code>optional string target_id = 1;</code>\n     */\n    public boolean hasTargetId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional string target_id = 1;</code>\n     */\n    public java.lang.String getTargetId() {\n      java.lang.Object ref = targetId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          targetId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string target_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTargetIdBytes() {\n      java.lang.Object ref = targetId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        targetId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string name = 2;\n    public static final int NAME_FIELD_NUMBER = 2;\n    private java.lang.Object name_;\n    /**\n     * <code>required string name = 2;</code>\n     */\n    public boolean hasName() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string name = 2;</code>\n     */\n    public java.lang.String getName() {\n      java.lang.Object ref = name_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          name_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string name = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getNameBytes() {\n      java.lang.Object ref = name_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        name_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string portrait = 3;\n    public static final int PORTRAIT_FIELD_NUMBER = 3;\n    private java.lang.Object portrait_;\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    public boolean hasPortrait() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    public java.lang.String getPortrait() {\n      java.lang.Object ref = portrait_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          portrait_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getPortraitBytes() {\n      java.lang.Object ref = portrait_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        portrait_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string owner = 4;\n    public static final int OWNER_FIELD_NUMBER = 4;\n    private java.lang.Object owner_;\n    /**\n     * <code>optional string owner = 4;</code>\n     */\n    public boolean hasOwner() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional string owner = 4;</code>\n     */\n    public java.lang.String getOwner() {\n      java.lang.Object ref = owner_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          owner_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string owner = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getOwnerBytes() {\n      java.lang.Object ref = owner_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        owner_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 type = 5;\n    public static final int TYPE_FIELD_NUMBER = 5;\n    private int type_;\n    /**\n     * <code>required int32 type = 5;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>required int32 type = 5;</code>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    // optional int32 member_count = 6;\n    public static final int MEMBER_COUNT_FIELD_NUMBER = 6;\n    private int memberCount_;\n    /**\n     * <code>optional int32 member_count = 6;</code>\n     */\n    public boolean hasMemberCount() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional int32 member_count = 6;</code>\n     */\n    public int getMemberCount() {\n      return memberCount_;\n    }\n\n    // optional string extra = 7;\n    public static final int EXTRA_FIELD_NUMBER = 7;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000040) == 0x00000040);\n    }\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int64 update_dt = 8;\n    public static final int UPDATE_DT_FIELD_NUMBER = 8;\n    private long updateDt_;\n    /**\n     * <code>optional int64 update_dt = 8;</code>\n     */\n    public boolean hasUpdateDt() {\n      return ((bitField0_ & 0x00000080) == 0x00000080);\n    }\n    /**\n     * <code>optional int64 update_dt = 8;</code>\n     */\n    public long getUpdateDt() {\n      return updateDt_;\n    }\n\n    // optional int64 member_update_dt = 9;\n    public static final int MEMBER_UPDATE_DT_FIELD_NUMBER = 9;\n    private long memberUpdateDt_;\n    /**\n     * <code>optional int64 member_update_dt = 9;</code>\n     */\n    public boolean hasMemberUpdateDt() {\n      return ((bitField0_ & 0x00000100) == 0x00000100);\n    }\n    /**\n     * <code>optional int64 member_update_dt = 9;</code>\n     */\n    public long getMemberUpdateDt() {\n      return memberUpdateDt_;\n    }\n\n    // optional int32 mute = 10;\n    public static final int MUTE_FIELD_NUMBER = 10;\n    private int mute_;\n    /**\n     * <code>optional int32 mute = 10;</code>\n     */\n    public boolean hasMute() {\n      return ((bitField0_ & 0x00000200) == 0x00000200);\n    }\n    /**\n     * <code>optional int32 mute = 10;</code>\n     */\n    public int getMute() {\n      return mute_;\n    }\n\n    // optional int32 join_type = 11;\n    public static final int JOIN_TYPE_FIELD_NUMBER = 11;\n    private int joinType_;\n    /**\n     * <code>optional int32 join_type = 11;</code>\n     */\n    public boolean hasJoinType() {\n      return ((bitField0_ & 0x00000400) == 0x00000400);\n    }\n    /**\n     * <code>optional int32 join_type = 11;</code>\n     */\n    public int getJoinType() {\n      return joinType_;\n    }\n\n    // optional int32 private_chat = 12;\n    public static final int PRIVATE_CHAT_FIELD_NUMBER = 12;\n    private int privateChat_;\n    /**\n     * <code>optional int32 private_chat = 12;</code>\n     */\n    public boolean hasPrivateChat() {\n      return ((bitField0_ & 0x00000800) == 0x00000800);\n    }\n    /**\n     * <code>optional int32 private_chat = 12;</code>\n     */\n    public int getPrivateChat() {\n      return privateChat_;\n    }\n\n    // optional int32 searchable = 13;\n    public static final int SEARCHABLE_FIELD_NUMBER = 13;\n    private int searchable_;\n    /**\n     * <code>optional int32 searchable = 13;</code>\n     */\n    public boolean hasSearchable() {\n      return ((bitField0_ & 0x00001000) == 0x00001000);\n    }\n    /**\n     * <code>optional int32 searchable = 13;</code>\n     */\n    public int getSearchable() {\n      return searchable_;\n    }\n\n    // optional int32 max_member_count = 14;\n    public static final int MAX_MEMBER_COUNT_FIELD_NUMBER = 14;\n    private int maxMemberCount_;\n    /**\n     * <code>optional int32 max_member_count = 14;</code>\n     */\n    public boolean hasMaxMemberCount() {\n      return ((bitField0_ & 0x00002000) == 0x00002000);\n    }\n    /**\n     * <code>optional int32 max_member_count = 14;</code>\n     */\n    public int getMaxMemberCount() {\n      return maxMemberCount_;\n    }\n\n    // optional int32 history_message = 15;\n    public static final int HISTORY_MESSAGE_FIELD_NUMBER = 15;\n    private int historyMessage_;\n    /**\n     * <code>optional int32 history_message = 15;</code>\n     */\n    public boolean hasHistoryMessage() {\n      return ((bitField0_ & 0x00004000) == 0x00004000);\n    }\n    /**\n     * <code>optional int32 history_message = 15;</code>\n     */\n    public int getHistoryMessage() {\n      return historyMessage_;\n    }\n\n    // optional int32 super_group = 16;\n    public static final int SUPER_GROUP_FIELD_NUMBER = 16;\n    private int superGroup_;\n    /**\n     * <code>optional int32 super_group = 16;</code>\n     */\n    public boolean hasSuperGroup() {\n      return ((bitField0_ & 0x00008000) == 0x00008000);\n    }\n    /**\n     * <code>optional int32 super_group = 16;</code>\n     */\n    public int getSuperGroup() {\n      return superGroup_;\n    }\n\n    // optional int32 deleted = 17;\n    public static final int DELETED_FIELD_NUMBER = 17;\n    private int deleted_;\n    /**\n     * <code>optional int32 deleted = 17;</code>\n     */\n    public boolean hasDeleted() {\n      return ((bitField0_ & 0x00010000) == 0x00010000);\n    }\n    /**\n     * <code>optional int32 deleted = 17;</code>\n     */\n    public int getDeleted() {\n      return deleted_;\n    }\n\n    private void initFields() {\n      targetId_ = \"\";\n      name_ = \"\";\n      portrait_ = \"\";\n      owner_ = \"\";\n      type_ = 0;\n      memberCount_ = 0;\n      extra_ = \"\";\n      updateDt_ = 0L;\n      memberUpdateDt_ = 0L;\n      mute_ = 0;\n      joinType_ = 0;\n      privateChat_ = 0;\n      searchable_ = 0;\n      maxMemberCount_ = 0;\n      historyMessage_ = 0;\n      superGroup_ = 0;\n      deleted_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasName()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getTargetIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getNameBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getPortraitBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(4, getOwnerBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeInt32(5, type_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeInt32(6, memberCount_);\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        output.writeBytes(7, getExtraBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        output.writeInt64(8, updateDt_);\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        output.writeInt64(9, memberUpdateDt_);\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        output.writeInt32(10, mute_);\n      }\n      if (((bitField0_ & 0x00000400) == 0x00000400)) {\n        output.writeInt32(11, joinType_);\n      }\n      if (((bitField0_ & 0x00000800) == 0x00000800)) {\n        output.writeInt32(12, privateChat_);\n      }\n      if (((bitField0_ & 0x00001000) == 0x00001000)) {\n        output.writeInt32(13, searchable_);\n      }\n      if (((bitField0_ & 0x00002000) == 0x00002000)) {\n        output.writeInt32(14, maxMemberCount_);\n      }\n      if (((bitField0_ & 0x00004000) == 0x00004000)) {\n        output.writeInt32(15, historyMessage_);\n      }\n      if (((bitField0_ & 0x00008000) == 0x00008000)) {\n        output.writeInt32(16, superGroup_);\n      }\n      if (((bitField0_ & 0x00010000) == 0x00010000)) {\n        output.writeInt32(17, deleted_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getTargetIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getNameBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getPortraitBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, getOwnerBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(5, type_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(6, memberCount_);\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(7, getExtraBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(8, updateDt_);\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(9, memberUpdateDt_);\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(10, mute_);\n      }\n      if (((bitField0_ & 0x00000400) == 0x00000400)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(11, joinType_);\n      }\n      if (((bitField0_ & 0x00000800) == 0x00000800)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(12, privateChat_);\n      }\n      if (((bitField0_ & 0x00001000) == 0x00001000)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(13, searchable_);\n      }\n      if (((bitField0_ & 0x00002000) == 0x00002000)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(14, maxMemberCount_);\n      }\n      if (((bitField0_ & 0x00004000) == 0x00004000)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(15, historyMessage_);\n      }\n      if (((bitField0_ & 0x00008000) == 0x00008000)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(16, superGroup_);\n      }\n      if (((bitField0_ & 0x00010000) == 0x00010000)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(17, deleted_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.GroupInfo parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupInfo parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupInfo parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupInfo parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupInfo parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupInfo parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupInfo parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupInfo parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupInfo parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupInfo parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.GroupInfo prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code GroupInfo}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GroupInfo_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GroupInfo_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.GroupInfo.class, cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.GroupInfo.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        targetId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        name_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        portrait_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        owner_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000010);\n        memberCount_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000020);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000040);\n        updateDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000080);\n        memberUpdateDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000100);\n        mute_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000200);\n        joinType_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000400);\n        privateChat_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000800);\n        searchable_ = 0;\n        bitField0_ = (bitField0_ & ~0x00001000);\n        maxMemberCount_ = 0;\n        bitField0_ = (bitField0_ & ~0x00002000);\n        historyMessage_ = 0;\n        bitField0_ = (bitField0_ & ~0x00004000);\n        superGroup_ = 0;\n        bitField0_ = (bitField0_ & ~0x00008000);\n        deleted_ = 0;\n        bitField0_ = (bitField0_ & ~0x00010000);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GroupInfo_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GroupInfo getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.GroupInfo.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GroupInfo build() {\n        cn.wildfirechat.proto.WFCMessage.GroupInfo result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GroupInfo buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.GroupInfo result = new cn.wildfirechat.proto.WFCMessage.GroupInfo(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.targetId_ = targetId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.name_ = name_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.portrait_ = portrait_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.owner_ = owner_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.type_ = type_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.memberCount_ = memberCount_;\n        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {\n          to_bitField0_ |= 0x00000040;\n        }\n        result.extra_ = extra_;\n        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {\n          to_bitField0_ |= 0x00000080;\n        }\n        result.updateDt_ = updateDt_;\n        if (((from_bitField0_ & 0x00000100) == 0x00000100)) {\n          to_bitField0_ |= 0x00000100;\n        }\n        result.memberUpdateDt_ = memberUpdateDt_;\n        if (((from_bitField0_ & 0x00000200) == 0x00000200)) {\n          to_bitField0_ |= 0x00000200;\n        }\n        result.mute_ = mute_;\n        if (((from_bitField0_ & 0x00000400) == 0x00000400)) {\n          to_bitField0_ |= 0x00000400;\n        }\n        result.joinType_ = joinType_;\n        if (((from_bitField0_ & 0x00000800) == 0x00000800)) {\n          to_bitField0_ |= 0x00000800;\n        }\n        result.privateChat_ = privateChat_;\n        if (((from_bitField0_ & 0x00001000) == 0x00001000)) {\n          to_bitField0_ |= 0x00001000;\n        }\n        result.searchable_ = searchable_;\n        if (((from_bitField0_ & 0x00002000) == 0x00002000)) {\n          to_bitField0_ |= 0x00002000;\n        }\n        result.maxMemberCount_ = maxMemberCount_;\n        if (((from_bitField0_ & 0x00004000) == 0x00004000)) {\n          to_bitField0_ |= 0x00004000;\n        }\n        result.historyMessage_ = historyMessage_;\n        if (((from_bitField0_ & 0x00008000) == 0x00008000)) {\n          to_bitField0_ |= 0x00008000;\n        }\n        result.superGroup_ = superGroup_;\n        if (((from_bitField0_ & 0x00010000) == 0x00010000)) {\n          to_bitField0_ |= 0x00010000;\n        }\n        result.deleted_ = deleted_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.GroupInfo) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.GroupInfo)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.GroupInfo other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.GroupInfo.getDefaultInstance()) return this;\n        if (other.hasTargetId()) {\n          bitField0_ |= 0x00000001;\n          targetId_ = other.targetId_;\n          onChanged();\n        }\n        if (other.hasName()) {\n          bitField0_ |= 0x00000002;\n          name_ = other.name_;\n          onChanged();\n        }\n        if (other.hasPortrait()) {\n          bitField0_ |= 0x00000004;\n          portrait_ = other.portrait_;\n          onChanged();\n        }\n        if (other.hasOwner()) {\n          bitField0_ |= 0x00000008;\n          owner_ = other.owner_;\n          onChanged();\n        }\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        if (other.hasMemberCount()) {\n          setMemberCount(other.getMemberCount());\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000040;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        if (other.hasUpdateDt()) {\n          setUpdateDt(other.getUpdateDt());\n        }\n        if (other.hasMemberUpdateDt()) {\n          setMemberUpdateDt(other.getMemberUpdateDt());\n        }\n        if (other.hasMute()) {\n          setMute(other.getMute());\n        }\n        if (other.hasJoinType()) {\n          setJoinType(other.getJoinType());\n        }\n        if (other.hasPrivateChat()) {\n          setPrivateChat(other.getPrivateChat());\n        }\n        if (other.hasSearchable()) {\n          setSearchable(other.getSearchable());\n        }\n        if (other.hasMaxMemberCount()) {\n          setMaxMemberCount(other.getMaxMemberCount());\n        }\n        if (other.hasHistoryMessage()) {\n          setHistoryMessage(other.getHistoryMessage());\n        }\n        if (other.hasSuperGroup()) {\n          setSuperGroup(other.getSuperGroup());\n        }\n        if (other.hasDeleted()) {\n          setDeleted(other.getDeleted());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasName()) {\n          \n          return false;\n        }\n        if (!hasType()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.GroupInfo parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.GroupInfo) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // optional string target_id = 1;\n      private java.lang.Object targetId_ = \"\";\n      /**\n       * <code>optional string target_id = 1;</code>\n       */\n      public boolean hasTargetId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional string target_id = 1;</code>\n       */\n      public java.lang.String getTargetId() {\n        java.lang.Object ref = targetId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          targetId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string target_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTargetIdBytes() {\n        java.lang.Object ref = targetId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          targetId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string target_id = 1;</code>\n       */\n      public Builder setTargetId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        targetId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string target_id = 1;</code>\n       */\n      public Builder clearTargetId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        targetId_ = getDefaultInstance().getTargetId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string target_id = 1;</code>\n       */\n      public Builder setTargetIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        targetId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string name = 2;\n      private java.lang.Object name_ = \"\";\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public boolean hasName() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public java.lang.String getName() {\n        java.lang.Object ref = name_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          name_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getNameBytes() {\n        java.lang.Object ref = name_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          name_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public Builder setName(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        name_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public Builder clearName() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        name_ = getDefaultInstance().getName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public Builder setNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        name_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string portrait = 3;\n      private java.lang.Object portrait_ = \"\";\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public boolean hasPortrait() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public java.lang.String getPortrait() {\n        java.lang.Object ref = portrait_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          portrait_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getPortraitBytes() {\n        java.lang.Object ref = portrait_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          portrait_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public Builder setPortrait(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        portrait_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public Builder clearPortrait() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        portrait_ = getDefaultInstance().getPortrait();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public Builder setPortraitBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        portrait_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string owner = 4;\n      private java.lang.Object owner_ = \"\";\n      /**\n       * <code>optional string owner = 4;</code>\n       */\n      public boolean hasOwner() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional string owner = 4;</code>\n       */\n      public java.lang.String getOwner() {\n        java.lang.Object ref = owner_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          owner_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string owner = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getOwnerBytes() {\n        java.lang.Object ref = owner_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          owner_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string owner = 4;</code>\n       */\n      public Builder setOwner(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        owner_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string owner = 4;</code>\n       */\n      public Builder clearOwner() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        owner_ = getDefaultInstance().getOwner();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string owner = 4;</code>\n       */\n      public Builder setOwnerBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        owner_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 type = 5;\n      private int type_ ;\n      /**\n       * <code>required int32 type = 5;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>required int32 type = 5;</code>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>required int32 type = 5;</code>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00000010;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 type = 5;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 member_count = 6;\n      private int memberCount_ ;\n      /**\n       * <code>optional int32 member_count = 6;</code>\n       */\n      public boolean hasMemberCount() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional int32 member_count = 6;</code>\n       */\n      public int getMemberCount() {\n        return memberCount_;\n      }\n      /**\n       * <code>optional int32 member_count = 6;</code>\n       */\n      public Builder setMemberCount(int value) {\n        bitField0_ |= 0x00000020;\n        memberCount_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 member_count = 6;</code>\n       */\n      public Builder clearMemberCount() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        memberCount_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional string extra = 7;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000040) == 0x00000040);\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000040);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 update_dt = 8;\n      private long updateDt_ ;\n      /**\n       * <code>optional int64 update_dt = 8;</code>\n       */\n      public boolean hasUpdateDt() {\n        return ((bitField0_ & 0x00000080) == 0x00000080);\n      }\n      /**\n       * <code>optional int64 update_dt = 8;</code>\n       */\n      public long getUpdateDt() {\n        return updateDt_;\n      }\n      /**\n       * <code>optional int64 update_dt = 8;</code>\n       */\n      public Builder setUpdateDt(long value) {\n        bitField0_ |= 0x00000080;\n        updateDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 update_dt = 8;</code>\n       */\n      public Builder clearUpdateDt() {\n        bitField0_ = (bitField0_ & ~0x00000080);\n        updateDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 member_update_dt = 9;\n      private long memberUpdateDt_ ;\n      /**\n       * <code>optional int64 member_update_dt = 9;</code>\n       */\n      public boolean hasMemberUpdateDt() {\n        return ((bitField0_ & 0x00000100) == 0x00000100);\n      }\n      /**\n       * <code>optional int64 member_update_dt = 9;</code>\n       */\n      public long getMemberUpdateDt() {\n        return memberUpdateDt_;\n      }\n      /**\n       * <code>optional int64 member_update_dt = 9;</code>\n       */\n      public Builder setMemberUpdateDt(long value) {\n        bitField0_ |= 0x00000100;\n        memberUpdateDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 member_update_dt = 9;</code>\n       */\n      public Builder clearMemberUpdateDt() {\n        bitField0_ = (bitField0_ & ~0x00000100);\n        memberUpdateDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 mute = 10;\n      private int mute_ ;\n      /**\n       * <code>optional int32 mute = 10;</code>\n       */\n      public boolean hasMute() {\n        return ((bitField0_ & 0x00000200) == 0x00000200);\n      }\n      /**\n       * <code>optional int32 mute = 10;</code>\n       */\n      public int getMute() {\n        return mute_;\n      }\n      /**\n       * <code>optional int32 mute = 10;</code>\n       */\n      public Builder setMute(int value) {\n        bitField0_ |= 0x00000200;\n        mute_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 mute = 10;</code>\n       */\n      public Builder clearMute() {\n        bitField0_ = (bitField0_ & ~0x00000200);\n        mute_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 join_type = 11;\n      private int joinType_ ;\n      /**\n       * <code>optional int32 join_type = 11;</code>\n       */\n      public boolean hasJoinType() {\n        return ((bitField0_ & 0x00000400) == 0x00000400);\n      }\n      /**\n       * <code>optional int32 join_type = 11;</code>\n       */\n      public int getJoinType() {\n        return joinType_;\n      }\n      /**\n       * <code>optional int32 join_type = 11;</code>\n       */\n      public Builder setJoinType(int value) {\n        bitField0_ |= 0x00000400;\n        joinType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 join_type = 11;</code>\n       */\n      public Builder clearJoinType() {\n        bitField0_ = (bitField0_ & ~0x00000400);\n        joinType_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 private_chat = 12;\n      private int privateChat_ ;\n      /**\n       * <code>optional int32 private_chat = 12;</code>\n       */\n      public boolean hasPrivateChat() {\n        return ((bitField0_ & 0x00000800) == 0x00000800);\n      }\n      /**\n       * <code>optional int32 private_chat = 12;</code>\n       */\n      public int getPrivateChat() {\n        return privateChat_;\n      }\n      /**\n       * <code>optional int32 private_chat = 12;</code>\n       */\n      public Builder setPrivateChat(int value) {\n        bitField0_ |= 0x00000800;\n        privateChat_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 private_chat = 12;</code>\n       */\n      public Builder clearPrivateChat() {\n        bitField0_ = (bitField0_ & ~0x00000800);\n        privateChat_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 searchable = 13;\n      private int searchable_ ;\n      /**\n       * <code>optional int32 searchable = 13;</code>\n       */\n      public boolean hasSearchable() {\n        return ((bitField0_ & 0x00001000) == 0x00001000);\n      }\n      /**\n       * <code>optional int32 searchable = 13;</code>\n       */\n      public int getSearchable() {\n        return searchable_;\n      }\n      /**\n       * <code>optional int32 searchable = 13;</code>\n       */\n      public Builder setSearchable(int value) {\n        bitField0_ |= 0x00001000;\n        searchable_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 searchable = 13;</code>\n       */\n      public Builder clearSearchable() {\n        bitField0_ = (bitField0_ & ~0x00001000);\n        searchable_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 max_member_count = 14;\n      private int maxMemberCount_ ;\n      /**\n       * <code>optional int32 max_member_count = 14;</code>\n       */\n      public boolean hasMaxMemberCount() {\n        return ((bitField0_ & 0x00002000) == 0x00002000);\n      }\n      /**\n       * <code>optional int32 max_member_count = 14;</code>\n       */\n      public int getMaxMemberCount() {\n        return maxMemberCount_;\n      }\n      /**\n       * <code>optional int32 max_member_count = 14;</code>\n       */\n      public Builder setMaxMemberCount(int value) {\n        bitField0_ |= 0x00002000;\n        maxMemberCount_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 max_member_count = 14;</code>\n       */\n      public Builder clearMaxMemberCount() {\n        bitField0_ = (bitField0_ & ~0x00002000);\n        maxMemberCount_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 history_message = 15;\n      private int historyMessage_ ;\n      /**\n       * <code>optional int32 history_message = 15;</code>\n       */\n      public boolean hasHistoryMessage() {\n        return ((bitField0_ & 0x00004000) == 0x00004000);\n      }\n      /**\n       * <code>optional int32 history_message = 15;</code>\n       */\n      public int getHistoryMessage() {\n        return historyMessage_;\n      }\n      /**\n       * <code>optional int32 history_message = 15;</code>\n       */\n      public Builder setHistoryMessage(int value) {\n        bitField0_ |= 0x00004000;\n        historyMessage_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 history_message = 15;</code>\n       */\n      public Builder clearHistoryMessage() {\n        bitField0_ = (bitField0_ & ~0x00004000);\n        historyMessage_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 super_group = 16;\n      private int superGroup_ ;\n      /**\n       * <code>optional int32 super_group = 16;</code>\n       */\n      public boolean hasSuperGroup() {\n        return ((bitField0_ & 0x00008000) == 0x00008000);\n      }\n      /**\n       * <code>optional int32 super_group = 16;</code>\n       */\n      public int getSuperGroup() {\n        return superGroup_;\n      }\n      /**\n       * <code>optional int32 super_group = 16;</code>\n       */\n      public Builder setSuperGroup(int value) {\n        bitField0_ |= 0x00008000;\n        superGroup_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 super_group = 16;</code>\n       */\n      public Builder clearSuperGroup() {\n        bitField0_ = (bitField0_ & ~0x00008000);\n        superGroup_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 deleted = 17;\n      private int deleted_ ;\n      /**\n       * <code>optional int32 deleted = 17;</code>\n       */\n      public boolean hasDeleted() {\n        return ((bitField0_ & 0x00010000) == 0x00010000);\n      }\n      /**\n       * <code>optional int32 deleted = 17;</code>\n       */\n      public int getDeleted() {\n        return deleted_;\n      }\n      /**\n       * <code>optional int32 deleted = 17;</code>\n       */\n      public Builder setDeleted(int value) {\n        bitField0_ |= 0x00010000;\n        deleted_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 deleted = 17;</code>\n       */\n      public Builder clearDeleted() {\n        bitField0_ = (bitField0_ & ~0x00010000);\n        deleted_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:GroupInfo)\n    }\n\n    static {\n      defaultInstance = new GroupInfo(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:GroupInfo)\n  }\n\n  public interface GroupMemberOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string member_id = 1;\n    /**\n     * <code>required string member_id = 1;</code>\n     */\n    boolean hasMemberId();\n    /**\n     * <code>required string member_id = 1;</code>\n     */\n    java.lang.String getMemberId();\n    /**\n     * <code>required string member_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getMemberIdBytes();\n\n    // optional string alias = 2;\n    /**\n     * <code>optional string alias = 2;</code>\n     */\n    boolean hasAlias();\n    /**\n     * <code>optional string alias = 2;</code>\n     */\n    java.lang.String getAlias();\n    /**\n     * <code>optional string alias = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getAliasBytes();\n\n    // required int32 type = 3;\n    /**\n     * <code>required int32 type = 3;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>required int32 type = 3;</code>\n     */\n    int getType();\n\n    // optional int64 update_dt = 4;\n    /**\n     * <code>optional int64 update_dt = 4;</code>\n     */\n    boolean hasUpdateDt();\n    /**\n     * <code>optional int64 update_dt = 4;</code>\n     */\n    long getUpdateDt();\n\n    // optional int64 create_dt = 5;\n    /**\n     * <code>optional int64 create_dt = 5;</code>\n     */\n    boolean hasCreateDt();\n    /**\n     * <code>optional int64 create_dt = 5;</code>\n     */\n    long getCreateDt();\n\n    // optional string extra = 6;\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n  }\n  /**\n   * Protobuf type {@code GroupMember}\n   */\n  public static final class GroupMember extends\n      com.google.protobuf.GeneratedMessage\n      implements GroupMemberOrBuilder {\n    // Use GroupMember.newBuilder() to construct.\n    private GroupMember(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private GroupMember(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final GroupMember defaultInstance;\n    public static GroupMember getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public GroupMember getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private GroupMember(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              memberId_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              alias_ = input.readBytes();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              type_ = input.readInt32();\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000008;\n              updateDt_ = input.readInt64();\n              break;\n            }\n            case 40: {\n              bitField0_ |= 0x00000010;\n              createDt_ = input.readInt64();\n              break;\n            }\n            case 50: {\n              bitField0_ |= 0x00000020;\n              extra_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GroupMember_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GroupMember_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.GroupMember.class, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<GroupMember> PARSER =\n        new com.google.protobuf.AbstractParser<GroupMember>() {\n      public GroupMember parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new GroupMember(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<GroupMember> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string member_id = 1;\n    public static final int MEMBER_ID_FIELD_NUMBER = 1;\n    private java.lang.Object memberId_;\n    /**\n     * <code>required string member_id = 1;</code>\n     */\n    public boolean hasMemberId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string member_id = 1;</code>\n     */\n    public java.lang.String getMemberId() {\n      java.lang.Object ref = memberId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          memberId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string member_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getMemberIdBytes() {\n      java.lang.Object ref = memberId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        memberId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string alias = 2;\n    public static final int ALIAS_FIELD_NUMBER = 2;\n    private java.lang.Object alias_;\n    /**\n     * <code>optional string alias = 2;</code>\n     */\n    public boolean hasAlias() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional string alias = 2;</code>\n     */\n    public java.lang.String getAlias() {\n      java.lang.Object ref = alias_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          alias_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string alias = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getAliasBytes() {\n      java.lang.Object ref = alias_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        alias_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 type = 3;\n    public static final int TYPE_FIELD_NUMBER = 3;\n    private int type_;\n    /**\n     * <code>required int32 type = 3;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required int32 type = 3;</code>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    // optional int64 update_dt = 4;\n    public static final int UPDATE_DT_FIELD_NUMBER = 4;\n    private long updateDt_;\n    /**\n     * <code>optional int64 update_dt = 4;</code>\n     */\n    public boolean hasUpdateDt() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional int64 update_dt = 4;</code>\n     */\n    public long getUpdateDt() {\n      return updateDt_;\n    }\n\n    // optional int64 create_dt = 5;\n    public static final int CREATE_DT_FIELD_NUMBER = 5;\n    private long createDt_;\n    /**\n     * <code>optional int64 create_dt = 5;</code>\n     */\n    public boolean hasCreateDt() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional int64 create_dt = 5;</code>\n     */\n    public long getCreateDt() {\n      return createDt_;\n    }\n\n    // optional string extra = 6;\n    public static final int EXTRA_FIELD_NUMBER = 6;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      memberId_ = \"\";\n      alias_ = \"\";\n      type_ = 0;\n      updateDt_ = 0L;\n      createDt_ = 0L;\n      extra_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasMemberId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getMemberIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getAliasBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt32(3, type_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeInt64(4, updateDt_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeInt64(5, createDt_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeBytes(6, getExtraBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getMemberIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getAliasBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(3, type_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(4, updateDt_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(5, createDt_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(6, getExtraBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.GroupMember parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupMember parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupMember parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupMember parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupMember parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupMember parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupMember parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupMember parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupMember parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GroupMember parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.GroupMember prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code GroupMember}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GroupMember_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GroupMember_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.GroupMember.class, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.GroupMember.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        memberId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        alias_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        updateDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        createDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000010);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000020);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GroupMember_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GroupMember getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.GroupMember.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GroupMember build() {\n        cn.wildfirechat.proto.WFCMessage.GroupMember result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GroupMember buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.GroupMember result = new cn.wildfirechat.proto.WFCMessage.GroupMember(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.memberId_ = memberId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.alias_ = alias_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.type_ = type_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.updateDt_ = updateDt_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.createDt_ = createDt_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.extra_ = extra_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.GroupMember) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.GroupMember)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.GroupMember other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.GroupMember.getDefaultInstance()) return this;\n        if (other.hasMemberId()) {\n          bitField0_ |= 0x00000001;\n          memberId_ = other.memberId_;\n          onChanged();\n        }\n        if (other.hasAlias()) {\n          bitField0_ |= 0x00000002;\n          alias_ = other.alias_;\n          onChanged();\n        }\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        if (other.hasUpdateDt()) {\n          setUpdateDt(other.getUpdateDt());\n        }\n        if (other.hasCreateDt()) {\n          setCreateDt(other.getCreateDt());\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000020;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasMemberId()) {\n          \n          return false;\n        }\n        if (!hasType()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.GroupMember parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.GroupMember) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string member_id = 1;\n      private java.lang.Object memberId_ = \"\";\n      /**\n       * <code>required string member_id = 1;</code>\n       */\n      public boolean hasMemberId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string member_id = 1;</code>\n       */\n      public java.lang.String getMemberId() {\n        java.lang.Object ref = memberId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          memberId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string member_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getMemberIdBytes() {\n        java.lang.Object ref = memberId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          memberId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string member_id = 1;</code>\n       */\n      public Builder setMemberId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        memberId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string member_id = 1;</code>\n       */\n      public Builder clearMemberId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        memberId_ = getDefaultInstance().getMemberId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string member_id = 1;</code>\n       */\n      public Builder setMemberIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        memberId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string alias = 2;\n      private java.lang.Object alias_ = \"\";\n      /**\n       * <code>optional string alias = 2;</code>\n       */\n      public boolean hasAlias() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional string alias = 2;</code>\n       */\n      public java.lang.String getAlias() {\n        java.lang.Object ref = alias_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          alias_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string alias = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getAliasBytes() {\n        java.lang.Object ref = alias_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          alias_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string alias = 2;</code>\n       */\n      public Builder setAlias(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        alias_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string alias = 2;</code>\n       */\n      public Builder clearAlias() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        alias_ = getDefaultInstance().getAlias();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string alias = 2;</code>\n       */\n      public Builder setAliasBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        alias_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 type = 3;\n      private int type_ ;\n      /**\n       * <code>required int32 type = 3;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required int32 type = 3;</code>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>required int32 type = 3;</code>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00000004;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 type = 3;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 update_dt = 4;\n      private long updateDt_ ;\n      /**\n       * <code>optional int64 update_dt = 4;</code>\n       */\n      public boolean hasUpdateDt() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional int64 update_dt = 4;</code>\n       */\n      public long getUpdateDt() {\n        return updateDt_;\n      }\n      /**\n       * <code>optional int64 update_dt = 4;</code>\n       */\n      public Builder setUpdateDt(long value) {\n        bitField0_ |= 0x00000008;\n        updateDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 update_dt = 4;</code>\n       */\n      public Builder clearUpdateDt() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        updateDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 create_dt = 5;\n      private long createDt_ ;\n      /**\n       * <code>optional int64 create_dt = 5;</code>\n       */\n      public boolean hasCreateDt() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional int64 create_dt = 5;</code>\n       */\n      public long getCreateDt() {\n        return createDt_;\n      }\n      /**\n       * <code>optional int64 create_dt = 5;</code>\n       */\n      public Builder setCreateDt(long value) {\n        bitField0_ |= 0x00000010;\n        createDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 create_dt = 5;</code>\n       */\n      public Builder clearCreateDt() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        createDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional string extra = 6;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:GroupMember)\n    }\n\n    static {\n      defaultInstance = new GroupMember(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:GroupMember)\n  }\n\n  public interface GroupOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required .GroupInfo group_info = 1;\n    /**\n     * <code>required .GroupInfo group_info = 1;</code>\n     */\n    boolean hasGroupInfo();\n    /**\n     * <code>required .GroupInfo group_info = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.GroupInfo getGroupInfo();\n    /**\n     * <code>required .GroupInfo group_info = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder getGroupInfoOrBuilder();\n\n    // repeated .GroupMember members = 2;\n    /**\n     * <code>repeated .GroupMember members = 2;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> \n        getMembersList();\n    /**\n     * <code>repeated .GroupMember members = 2;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.GroupMember getMembers(int index);\n    /**\n     * <code>repeated .GroupMember members = 2;</code>\n     */\n    int getMembersCount();\n    /**\n     * <code>repeated .GroupMember members = 2;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> \n        getMembersOrBuilderList();\n    /**\n     * <code>repeated .GroupMember members = 2;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder getMembersOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code Group}\n   */\n  public static final class Group extends\n      com.google.protobuf.GeneratedMessage\n      implements GroupOrBuilder {\n    // Use Group.newBuilder() to construct.\n    private Group(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private Group(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final Group defaultInstance;\n    public static Group getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public Group getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Group(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                subBuilder = groupInfo_.toBuilder();\n              }\n              groupInfo_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.GroupInfo.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(groupInfo_);\n                groupInfo_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000001;\n              break;\n            }\n            case 18: {\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n                members_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.GroupMember>();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              members_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.GroupMember.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n          members_ = java.util.Collections.unmodifiableList(members_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_Group_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_Group_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.Group.class, cn.wildfirechat.proto.WFCMessage.Group.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<Group> PARSER =\n        new com.google.protobuf.AbstractParser<Group>() {\n      public Group parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Group(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Group> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required .GroupInfo group_info = 1;\n    public static final int GROUP_INFO_FIELD_NUMBER = 1;\n    private cn.wildfirechat.proto.WFCMessage.GroupInfo groupInfo_;\n    /**\n     * <code>required .GroupInfo group_info = 1;</code>\n     */\n    public boolean hasGroupInfo() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required .GroupInfo group_info = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.GroupInfo getGroupInfo() {\n      return groupInfo_;\n    }\n    /**\n     * <code>required .GroupInfo group_info = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder getGroupInfoOrBuilder() {\n      return groupInfo_;\n    }\n\n    // repeated .GroupMember members = 2;\n    public static final int MEMBERS_FIELD_NUMBER = 2;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> members_;\n    /**\n     * <code>repeated .GroupMember members = 2;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> getMembersList() {\n      return members_;\n    }\n    /**\n     * <code>repeated .GroupMember members = 2;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> \n        getMembersOrBuilderList() {\n      return members_;\n    }\n    /**\n     * <code>repeated .GroupMember members = 2;</code>\n     */\n    public int getMembersCount() {\n      return members_.size();\n    }\n    /**\n     * <code>repeated .GroupMember members = 2;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.GroupMember getMembers(int index) {\n      return members_.get(index);\n    }\n    /**\n     * <code>repeated .GroupMember members = 2;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder getMembersOrBuilder(\n        int index) {\n      return members_.get(index);\n    }\n\n    private void initFields() {\n      groupInfo_ = cn.wildfirechat.proto.WFCMessage.GroupInfo.getDefaultInstance();\n      members_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasGroupInfo()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!getGroupInfo().isInitialized()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      for (int i = 0; i < getMembersCount(); i++) {\n        if (!getMembers(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeMessage(1, groupInfo_);\n      }\n      for (int i = 0; i < members_.size(); i++) {\n        output.writeMessage(2, members_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, groupInfo_);\n      }\n      for (int i = 0; i < members_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(2, members_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.Group parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Group parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Group parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Group parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Group parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Group parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Group parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Group parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Group parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Group parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.Group prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code Group}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GroupOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Group_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Group_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.Group.class, cn.wildfirechat.proto.WFCMessage.Group.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.Group.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getGroupInfoFieldBuilder();\n          getMembersFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (groupInfoBuilder_ == null) {\n          groupInfo_ = cn.wildfirechat.proto.WFCMessage.GroupInfo.getDefaultInstance();\n        } else {\n          groupInfoBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000001);\n        if (membersBuilder_ == null) {\n          members_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000002);\n        } else {\n          membersBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Group_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Group getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.Group.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Group build() {\n        cn.wildfirechat.proto.WFCMessage.Group result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Group buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.Group result = new cn.wildfirechat.proto.WFCMessage.Group(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        if (groupInfoBuilder_ == null) {\n          result.groupInfo_ = groupInfo_;\n        } else {\n          result.groupInfo_ = groupInfoBuilder_.build();\n        }\n        if (membersBuilder_ == null) {\n          if (((bitField0_ & 0x00000002) == 0x00000002)) {\n            members_ = java.util.Collections.unmodifiableList(members_);\n            bitField0_ = (bitField0_ & ~0x00000002);\n          }\n          result.members_ = members_;\n        } else {\n          result.members_ = membersBuilder_.build();\n        }\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.Group) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.Group)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.Group other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.Group.getDefaultInstance()) return this;\n        if (other.hasGroupInfo()) {\n          mergeGroupInfo(other.getGroupInfo());\n        }\n        if (membersBuilder_ == null) {\n          if (!other.members_.isEmpty()) {\n            if (members_.isEmpty()) {\n              members_ = other.members_;\n              bitField0_ = (bitField0_ & ~0x00000002);\n            } else {\n              ensureMembersIsMutable();\n              members_.addAll(other.members_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.members_.isEmpty()) {\n            if (membersBuilder_.isEmpty()) {\n              membersBuilder_.dispose();\n              membersBuilder_ = null;\n              members_ = other.members_;\n              bitField0_ = (bitField0_ & ~0x00000002);\n              membersBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getMembersFieldBuilder() : null;\n            } else {\n              membersBuilder_.addAllMessages(other.members_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasGroupInfo()) {\n          \n          return false;\n        }\n        if (!getGroupInfo().isInitialized()) {\n          \n          return false;\n        }\n        for (int i = 0; i < getMembersCount(); i++) {\n          if (!getMembers(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.Group parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.Group) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required .GroupInfo group_info = 1;\n      private cn.wildfirechat.proto.WFCMessage.GroupInfo groupInfo_ = cn.wildfirechat.proto.WFCMessage.GroupInfo.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.GroupInfo, cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder, cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder> groupInfoBuilder_;\n      /**\n       * <code>required .GroupInfo group_info = 1;</code>\n       */\n      public boolean hasGroupInfo() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required .GroupInfo group_info = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupInfo getGroupInfo() {\n        if (groupInfoBuilder_ == null) {\n          return groupInfo_;\n        } else {\n          return groupInfoBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>required .GroupInfo group_info = 1;</code>\n       */\n      public Builder setGroupInfo(cn.wildfirechat.proto.WFCMessage.GroupInfo value) {\n        if (groupInfoBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          groupInfo_ = value;\n          onChanged();\n        } else {\n          groupInfoBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .GroupInfo group_info = 1;</code>\n       */\n      public Builder setGroupInfo(\n          cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder builderForValue) {\n        if (groupInfoBuilder_ == null) {\n          groupInfo_ = builderForValue.build();\n          onChanged();\n        } else {\n          groupInfoBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .GroupInfo group_info = 1;</code>\n       */\n      public Builder mergeGroupInfo(cn.wildfirechat.proto.WFCMessage.GroupInfo value) {\n        if (groupInfoBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001) &&\n              groupInfo_ != cn.wildfirechat.proto.WFCMessage.GroupInfo.getDefaultInstance()) {\n            groupInfo_ =\n              cn.wildfirechat.proto.WFCMessage.GroupInfo.newBuilder(groupInfo_).mergeFrom(value).buildPartial();\n          } else {\n            groupInfo_ = value;\n          }\n          onChanged();\n        } else {\n          groupInfoBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .GroupInfo group_info = 1;</code>\n       */\n      public Builder clearGroupInfo() {\n        if (groupInfoBuilder_ == null) {\n          groupInfo_ = cn.wildfirechat.proto.WFCMessage.GroupInfo.getDefaultInstance();\n          onChanged();\n        } else {\n          groupInfoBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000001);\n        return this;\n      }\n      /**\n       * <code>required .GroupInfo group_info = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder getGroupInfoBuilder() {\n        bitField0_ |= 0x00000001;\n        onChanged();\n        return getGroupInfoFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>required .GroupInfo group_info = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder getGroupInfoOrBuilder() {\n        if (groupInfoBuilder_ != null) {\n          return groupInfoBuilder_.getMessageOrBuilder();\n        } else {\n          return groupInfo_;\n        }\n      }\n      /**\n       * <code>required .GroupInfo group_info = 1;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.GroupInfo, cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder, cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder> \n          getGroupInfoFieldBuilder() {\n        if (groupInfoBuilder_ == null) {\n          groupInfoBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.GroupInfo, cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder, cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder>(\n                  groupInfo_,\n                  getParentForChildren(),\n                  isClean());\n          groupInfo_ = null;\n        }\n        return groupInfoBuilder_;\n      }\n\n      // repeated .GroupMember members = 2;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> members_ =\n        java.util.Collections.emptyList();\n      private void ensureMembersIsMutable() {\n        if (!((bitField0_ & 0x00000002) == 0x00000002)) {\n          members_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.GroupMember>(members_);\n          bitField0_ |= 0x00000002;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.GroupMember, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder, cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> membersBuilder_;\n\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> getMembersList() {\n        if (membersBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(members_);\n        } else {\n          return membersBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public int getMembersCount() {\n        if (membersBuilder_ == null) {\n          return members_.size();\n        } else {\n          return membersBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMember getMembers(int index) {\n        if (membersBuilder_ == null) {\n          return members_.get(index);\n        } else {\n          return membersBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public Builder setMembers(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupMember value) {\n        if (membersBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMembersIsMutable();\n          members_.set(index, value);\n          onChanged();\n        } else {\n          membersBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public Builder setMembers(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder builderForValue) {\n        if (membersBuilder_ == null) {\n          ensureMembersIsMutable();\n          members_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          membersBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public Builder addMembers(cn.wildfirechat.proto.WFCMessage.GroupMember value) {\n        if (membersBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMembersIsMutable();\n          members_.add(value);\n          onChanged();\n        } else {\n          membersBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public Builder addMembers(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupMember value) {\n        if (membersBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMembersIsMutable();\n          members_.add(index, value);\n          onChanged();\n        } else {\n          membersBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public Builder addMembers(\n          cn.wildfirechat.proto.WFCMessage.GroupMember.Builder builderForValue) {\n        if (membersBuilder_ == null) {\n          ensureMembersIsMutable();\n          members_.add(builderForValue.build());\n          onChanged();\n        } else {\n          membersBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public Builder addMembers(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder builderForValue) {\n        if (membersBuilder_ == null) {\n          ensureMembersIsMutable();\n          members_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          membersBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public Builder addAllMembers(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.GroupMember> values) {\n        if (membersBuilder_ == null) {\n          ensureMembersIsMutable();\n          super.addAll(values, members_);\n          onChanged();\n        } else {\n          membersBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public Builder clearMembers() {\n        if (membersBuilder_ == null) {\n          members_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000002);\n          onChanged();\n        } else {\n          membersBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public Builder removeMembers(int index) {\n        if (membersBuilder_ == null) {\n          ensureMembersIsMutable();\n          members_.remove(index);\n          onChanged();\n        } else {\n          membersBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMember.Builder getMembersBuilder(\n          int index) {\n        return getMembersFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder getMembersOrBuilder(\n          int index) {\n        if (membersBuilder_ == null) {\n          return members_.get(index);  } else {\n          return membersBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> \n           getMembersOrBuilderList() {\n        if (membersBuilder_ != null) {\n          return membersBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(members_);\n        }\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMember.Builder addMembersBuilder() {\n        return getMembersFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.GroupMember.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMember.Builder addMembersBuilder(\n          int index) {\n        return getMembersFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.GroupMember.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .GroupMember members = 2;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember.Builder> \n           getMembersBuilderList() {\n        return getMembersFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.GroupMember, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder, cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> \n          getMembersFieldBuilder() {\n        if (membersBuilder_ == null) {\n          membersBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.GroupMember, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder, cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder>(\n                  members_,\n                  ((bitField0_ & 0x00000002) == 0x00000002),\n                  getParentForChildren(),\n                  isClean());\n          members_ = null;\n        }\n        return membersBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:Group)\n    }\n\n    static {\n      defaultInstance = new Group(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:Group)\n  }\n\n  public interface ChannelMenuOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string type = 1;\n    /**\n     * <code>required string type = 1;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>required string type = 1;</code>\n     */\n    java.lang.String getType();\n    /**\n     * <code>required string type = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getTypeBytes();\n\n    // required string name = 2;\n    /**\n     * <code>required string name = 2;</code>\n     */\n    boolean hasName();\n    /**\n     * <code>required string name = 2;</code>\n     */\n    java.lang.String getName();\n    /**\n     * <code>required string name = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getNameBytes();\n\n    // optional string key = 3;\n    /**\n     * <code>optional string key = 3;</code>\n     */\n    boolean hasKey();\n    /**\n     * <code>optional string key = 3;</code>\n     */\n    java.lang.String getKey();\n    /**\n     * <code>optional string key = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getKeyBytes();\n\n    // optional string url = 4;\n    /**\n     * <code>optional string url = 4;</code>\n     */\n    boolean hasUrl();\n    /**\n     * <code>optional string url = 4;</code>\n     */\n    java.lang.String getUrl();\n    /**\n     * <code>optional string url = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getUrlBytes();\n\n    // optional string media_id = 5;\n    /**\n     * <code>optional string media_id = 5;</code>\n     */\n    boolean hasMediaId();\n    /**\n     * <code>optional string media_id = 5;</code>\n     */\n    java.lang.String getMediaId();\n    /**\n     * <code>optional string media_id = 5;</code>\n     */\n    com.google.protobuf.ByteString\n        getMediaIdBytes();\n\n    // optional string article_id = 6;\n    /**\n     * <code>optional string article_id = 6;</code>\n     */\n    boolean hasArticleId();\n    /**\n     * <code>optional string article_id = 6;</code>\n     */\n    java.lang.String getArticleId();\n    /**\n     * <code>optional string article_id = 6;</code>\n     */\n    com.google.protobuf.ByteString\n        getArticleIdBytes();\n\n    // optional string app_id = 7;\n    /**\n     * <code>optional string app_id = 7;</code>\n     */\n    boolean hasAppId();\n    /**\n     * <code>optional string app_id = 7;</code>\n     */\n    java.lang.String getAppId();\n    /**\n     * <code>optional string app_id = 7;</code>\n     */\n    com.google.protobuf.ByteString\n        getAppIdBytes();\n\n    // optional string app_page = 8;\n    /**\n     * <code>optional string app_page = 8;</code>\n     */\n    boolean hasAppPage();\n    /**\n     * <code>optional string app_page = 8;</code>\n     */\n    java.lang.String getAppPage();\n    /**\n     * <code>optional string app_page = 8;</code>\n     */\n    com.google.protobuf.ByteString\n        getAppPageBytes();\n\n    // repeated .ChannelMenu sub_menu = 9;\n    /**\n     * <code>repeated .ChannelMenu sub_menu = 9;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> \n        getSubMenuList();\n    /**\n     * <code>repeated .ChannelMenu sub_menu = 9;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.ChannelMenu getSubMenu(int index);\n    /**\n     * <code>repeated .ChannelMenu sub_menu = 9;</code>\n     */\n    int getSubMenuCount();\n    /**\n     * <code>repeated .ChannelMenu sub_menu = 9;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> \n        getSubMenuOrBuilderList();\n    /**\n     * <code>repeated .ChannelMenu sub_menu = 9;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder getSubMenuOrBuilder(\n        int index);\n\n    // optional string menu_id = 10;\n    /**\n     * <code>optional string menu_id = 10;</code>\n     */\n    boolean hasMenuId();\n    /**\n     * <code>optional string menu_id = 10;</code>\n     */\n    java.lang.String getMenuId();\n    /**\n     * <code>optional string menu_id = 10;</code>\n     */\n    com.google.protobuf.ByteString\n        getMenuIdBytes();\n\n    // optional string extra = 11;\n    /**\n     * <code>optional string extra = 11;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 11;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 11;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n  }\n  /**\n   * Protobuf type {@code ChannelMenu}\n   */\n  public static final class ChannelMenu extends\n      com.google.protobuf.GeneratedMessage\n      implements ChannelMenuOrBuilder {\n    // Use ChannelMenu.newBuilder() to construct.\n    private ChannelMenu(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ChannelMenu(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ChannelMenu defaultInstance;\n    public static ChannelMenu getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ChannelMenu getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ChannelMenu(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              type_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              name_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              key_ = input.readBytes();\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000008;\n              url_ = input.readBytes();\n              break;\n            }\n            case 42: {\n              bitField0_ |= 0x00000010;\n              mediaId_ = input.readBytes();\n              break;\n            }\n            case 50: {\n              bitField0_ |= 0x00000020;\n              articleId_ = input.readBytes();\n              break;\n            }\n            case 58: {\n              bitField0_ |= 0x00000040;\n              appId_ = input.readBytes();\n              break;\n            }\n            case 66: {\n              bitField0_ |= 0x00000080;\n              appPage_ = input.readBytes();\n              break;\n            }\n            case 74: {\n              if (!((mutable_bitField0_ & 0x00000100) == 0x00000100)) {\n                subMenu_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.ChannelMenu>();\n                mutable_bitField0_ |= 0x00000100;\n              }\n              subMenu_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.ChannelMenu.PARSER, extensionRegistry));\n              break;\n            }\n            case 82: {\n              bitField0_ |= 0x00000100;\n              menuId_ = input.readBytes();\n              break;\n            }\n            case 90: {\n              bitField0_ |= 0x00000200;\n              extra_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000100) == 0x00000100)) {\n          subMenu_ = java.util.Collections.unmodifiableList(subMenu_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelMenu_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelMenu_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ChannelMenu.class, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ChannelMenu> PARSER =\n        new com.google.protobuf.AbstractParser<ChannelMenu>() {\n      public ChannelMenu parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ChannelMenu(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ChannelMenu> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string type = 1;\n    public static final int TYPE_FIELD_NUMBER = 1;\n    private java.lang.Object type_;\n    /**\n     * <code>required string type = 1;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string type = 1;</code>\n     */\n    public java.lang.String getType() {\n      java.lang.Object ref = type_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          type_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string type = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTypeBytes() {\n      java.lang.Object ref = type_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        type_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string name = 2;\n    public static final int NAME_FIELD_NUMBER = 2;\n    private java.lang.Object name_;\n    /**\n     * <code>required string name = 2;</code>\n     */\n    public boolean hasName() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string name = 2;</code>\n     */\n    public java.lang.String getName() {\n      java.lang.Object ref = name_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          name_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string name = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getNameBytes() {\n      java.lang.Object ref = name_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        name_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string key = 3;\n    public static final int KEY_FIELD_NUMBER = 3;\n    private java.lang.Object key_;\n    /**\n     * <code>optional string key = 3;</code>\n     */\n    public boolean hasKey() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string key = 3;</code>\n     */\n    public java.lang.String getKey() {\n      java.lang.Object ref = key_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          key_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string key = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getKeyBytes() {\n      java.lang.Object ref = key_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        key_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string url = 4;\n    public static final int URL_FIELD_NUMBER = 4;\n    private java.lang.Object url_;\n    /**\n     * <code>optional string url = 4;</code>\n     */\n    public boolean hasUrl() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional string url = 4;</code>\n     */\n    public java.lang.String getUrl() {\n      java.lang.Object ref = url_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          url_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string url = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getUrlBytes() {\n      java.lang.Object ref = url_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        url_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string media_id = 5;\n    public static final int MEDIA_ID_FIELD_NUMBER = 5;\n    private java.lang.Object mediaId_;\n    /**\n     * <code>optional string media_id = 5;</code>\n     */\n    public boolean hasMediaId() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional string media_id = 5;</code>\n     */\n    public java.lang.String getMediaId() {\n      java.lang.Object ref = mediaId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          mediaId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string media_id = 5;</code>\n     */\n    public com.google.protobuf.ByteString\n        getMediaIdBytes() {\n      java.lang.Object ref = mediaId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        mediaId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string article_id = 6;\n    public static final int ARTICLE_ID_FIELD_NUMBER = 6;\n    private java.lang.Object articleId_;\n    /**\n     * <code>optional string article_id = 6;</code>\n     */\n    public boolean hasArticleId() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional string article_id = 6;</code>\n     */\n    public java.lang.String getArticleId() {\n      java.lang.Object ref = articleId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          articleId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string article_id = 6;</code>\n     */\n    public com.google.protobuf.ByteString\n        getArticleIdBytes() {\n      java.lang.Object ref = articleId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        articleId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string app_id = 7;\n    public static final int APP_ID_FIELD_NUMBER = 7;\n    private java.lang.Object appId_;\n    /**\n     * <code>optional string app_id = 7;</code>\n     */\n    public boolean hasAppId() {\n      return ((bitField0_ & 0x00000040) == 0x00000040);\n    }\n    /**\n     * <code>optional string app_id = 7;</code>\n     */\n    public java.lang.String getAppId() {\n      java.lang.Object ref = appId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          appId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string app_id = 7;</code>\n     */\n    public com.google.protobuf.ByteString\n        getAppIdBytes() {\n      java.lang.Object ref = appId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        appId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string app_page = 8;\n    public static final int APP_PAGE_FIELD_NUMBER = 8;\n    private java.lang.Object appPage_;\n    /**\n     * <code>optional string app_page = 8;</code>\n     */\n    public boolean hasAppPage() {\n      return ((bitField0_ & 0x00000080) == 0x00000080);\n    }\n    /**\n     * <code>optional string app_page = 8;</code>\n     */\n    public java.lang.String getAppPage() {\n      java.lang.Object ref = appPage_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          appPage_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string app_page = 8;</code>\n     */\n    public com.google.protobuf.ByteString\n        getAppPageBytes() {\n      java.lang.Object ref = appPage_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        appPage_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // repeated .ChannelMenu sub_menu = 9;\n    public static final int SUB_MENU_FIELD_NUMBER = 9;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> subMenu_;\n    /**\n     * <code>repeated .ChannelMenu sub_menu = 9;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> getSubMenuList() {\n      return subMenu_;\n    }\n    /**\n     * <code>repeated .ChannelMenu sub_menu = 9;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> \n        getSubMenuOrBuilderList() {\n      return subMenu_;\n    }\n    /**\n     * <code>repeated .ChannelMenu sub_menu = 9;</code>\n     */\n    public int getSubMenuCount() {\n      return subMenu_.size();\n    }\n    /**\n     * <code>repeated .ChannelMenu sub_menu = 9;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.ChannelMenu getSubMenu(int index) {\n      return subMenu_.get(index);\n    }\n    /**\n     * <code>repeated .ChannelMenu sub_menu = 9;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder getSubMenuOrBuilder(\n        int index) {\n      return subMenu_.get(index);\n    }\n\n    // optional string menu_id = 10;\n    public static final int MENU_ID_FIELD_NUMBER = 10;\n    private java.lang.Object menuId_;\n    /**\n     * <code>optional string menu_id = 10;</code>\n     */\n    public boolean hasMenuId() {\n      return ((bitField0_ & 0x00000100) == 0x00000100);\n    }\n    /**\n     * <code>optional string menu_id = 10;</code>\n     */\n    public java.lang.String getMenuId() {\n      java.lang.Object ref = menuId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          menuId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string menu_id = 10;</code>\n     */\n    public com.google.protobuf.ByteString\n        getMenuIdBytes() {\n      java.lang.Object ref = menuId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        menuId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string extra = 11;\n    public static final int EXTRA_FIELD_NUMBER = 11;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 11;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000200) == 0x00000200);\n    }\n    /**\n     * <code>optional string extra = 11;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 11;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      type_ = \"\";\n      name_ = \"\";\n      key_ = \"\";\n      url_ = \"\";\n      mediaId_ = \"\";\n      articleId_ = \"\";\n      appId_ = \"\";\n      appPage_ = \"\";\n      subMenu_ = java.util.Collections.emptyList();\n      menuId_ = \"\";\n      extra_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasName()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      for (int i = 0; i < getSubMenuCount(); i++) {\n        if (!getSubMenu(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getTypeBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getNameBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getKeyBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(4, getUrlBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeBytes(5, getMediaIdBytes());\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeBytes(6, getArticleIdBytes());\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        output.writeBytes(7, getAppIdBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        output.writeBytes(8, getAppPageBytes());\n      }\n      for (int i = 0; i < subMenu_.size(); i++) {\n        output.writeMessage(9, subMenu_.get(i));\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        output.writeBytes(10, getMenuIdBytes());\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        output.writeBytes(11, getExtraBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getTypeBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getNameBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getKeyBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, getUrlBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5, getMediaIdBytes());\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(6, getArticleIdBytes());\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(7, getAppIdBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(8, getAppPageBytes());\n      }\n      for (int i = 0; i < subMenu_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(9, subMenu_.get(i));\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(10, getMenuIdBytes());\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(11, getExtraBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenu parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenu parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenu parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenu parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenu parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenu parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenu parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenu parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenu parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenu parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ChannelMenu prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ChannelMenu}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelMenu_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelMenu_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ChannelMenu.class, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ChannelMenu.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getSubMenuFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        type_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        name_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        key_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        url_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        mediaId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000010);\n        articleId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000020);\n        appId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000040);\n        appPage_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000080);\n        if (subMenuBuilder_ == null) {\n          subMenu_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000100);\n        } else {\n          subMenuBuilder_.clear();\n        }\n        menuId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000200);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000400);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelMenu_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ChannelMenu.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu build() {\n        cn.wildfirechat.proto.WFCMessage.ChannelMenu result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ChannelMenu result = new cn.wildfirechat.proto.WFCMessage.ChannelMenu(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.type_ = type_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.name_ = name_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.key_ = key_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.url_ = url_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.mediaId_ = mediaId_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.articleId_ = articleId_;\n        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {\n          to_bitField0_ |= 0x00000040;\n        }\n        result.appId_ = appId_;\n        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {\n          to_bitField0_ |= 0x00000080;\n        }\n        result.appPage_ = appPage_;\n        if (subMenuBuilder_ == null) {\n          if (((bitField0_ & 0x00000100) == 0x00000100)) {\n            subMenu_ = java.util.Collections.unmodifiableList(subMenu_);\n            bitField0_ = (bitField0_ & ~0x00000100);\n          }\n          result.subMenu_ = subMenu_;\n        } else {\n          result.subMenu_ = subMenuBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000200) == 0x00000200)) {\n          to_bitField0_ |= 0x00000100;\n        }\n        result.menuId_ = menuId_;\n        if (((from_bitField0_ & 0x00000400) == 0x00000400)) {\n          to_bitField0_ |= 0x00000200;\n        }\n        result.extra_ = extra_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ChannelMenu) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ChannelMenu)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ChannelMenu other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ChannelMenu.getDefaultInstance()) return this;\n        if (other.hasType()) {\n          bitField0_ |= 0x00000001;\n          type_ = other.type_;\n          onChanged();\n        }\n        if (other.hasName()) {\n          bitField0_ |= 0x00000002;\n          name_ = other.name_;\n          onChanged();\n        }\n        if (other.hasKey()) {\n          bitField0_ |= 0x00000004;\n          key_ = other.key_;\n          onChanged();\n        }\n        if (other.hasUrl()) {\n          bitField0_ |= 0x00000008;\n          url_ = other.url_;\n          onChanged();\n        }\n        if (other.hasMediaId()) {\n          bitField0_ |= 0x00000010;\n          mediaId_ = other.mediaId_;\n          onChanged();\n        }\n        if (other.hasArticleId()) {\n          bitField0_ |= 0x00000020;\n          articleId_ = other.articleId_;\n          onChanged();\n        }\n        if (other.hasAppId()) {\n          bitField0_ |= 0x00000040;\n          appId_ = other.appId_;\n          onChanged();\n        }\n        if (other.hasAppPage()) {\n          bitField0_ |= 0x00000080;\n          appPage_ = other.appPage_;\n          onChanged();\n        }\n        if (subMenuBuilder_ == null) {\n          if (!other.subMenu_.isEmpty()) {\n            if (subMenu_.isEmpty()) {\n              subMenu_ = other.subMenu_;\n              bitField0_ = (bitField0_ & ~0x00000100);\n            } else {\n              ensureSubMenuIsMutable();\n              subMenu_.addAll(other.subMenu_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.subMenu_.isEmpty()) {\n            if (subMenuBuilder_.isEmpty()) {\n              subMenuBuilder_.dispose();\n              subMenuBuilder_ = null;\n              subMenu_ = other.subMenu_;\n              bitField0_ = (bitField0_ & ~0x00000100);\n              subMenuBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getSubMenuFieldBuilder() : null;\n            } else {\n              subMenuBuilder_.addAllMessages(other.subMenu_);\n            }\n          }\n        }\n        if (other.hasMenuId()) {\n          bitField0_ |= 0x00000200;\n          menuId_ = other.menuId_;\n          onChanged();\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000400;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasType()) {\n          \n          return false;\n        }\n        if (!hasName()) {\n          \n          return false;\n        }\n        for (int i = 0; i < getSubMenuCount(); i++) {\n          if (!getSubMenu(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ChannelMenu parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ChannelMenu) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string type = 1;\n      private java.lang.Object type_ = \"\";\n      /**\n       * <code>required string type = 1;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string type = 1;</code>\n       */\n      public java.lang.String getType() {\n        java.lang.Object ref = type_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          type_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string type = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTypeBytes() {\n        java.lang.Object ref = type_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          type_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string type = 1;</code>\n       */\n      public Builder setType(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string type = 1;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        type_ = getDefaultInstance().getType();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string type = 1;</code>\n       */\n      public Builder setTypeBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string name = 2;\n      private java.lang.Object name_ = \"\";\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public boolean hasName() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public java.lang.String getName() {\n        java.lang.Object ref = name_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          name_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getNameBytes() {\n        java.lang.Object ref = name_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          name_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public Builder setName(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        name_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public Builder clearName() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        name_ = getDefaultInstance().getName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public Builder setNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        name_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string key = 3;\n      private java.lang.Object key_ = \"\";\n      /**\n       * <code>optional string key = 3;</code>\n       */\n      public boolean hasKey() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional string key = 3;</code>\n       */\n      public java.lang.String getKey() {\n        java.lang.Object ref = key_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          key_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string key = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getKeyBytes() {\n        java.lang.Object ref = key_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          key_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string key = 3;</code>\n       */\n      public Builder setKey(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        key_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string key = 3;</code>\n       */\n      public Builder clearKey() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        key_ = getDefaultInstance().getKey();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string key = 3;</code>\n       */\n      public Builder setKeyBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        key_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string url = 4;\n      private java.lang.Object url_ = \"\";\n      /**\n       * <code>optional string url = 4;</code>\n       */\n      public boolean hasUrl() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional string url = 4;</code>\n       */\n      public java.lang.String getUrl() {\n        java.lang.Object ref = url_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          url_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string url = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getUrlBytes() {\n        java.lang.Object ref = url_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          url_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string url = 4;</code>\n       */\n      public Builder setUrl(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        url_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string url = 4;</code>\n       */\n      public Builder clearUrl() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        url_ = getDefaultInstance().getUrl();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string url = 4;</code>\n       */\n      public Builder setUrlBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        url_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string media_id = 5;\n      private java.lang.Object mediaId_ = \"\";\n      /**\n       * <code>optional string media_id = 5;</code>\n       */\n      public boolean hasMediaId() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional string media_id = 5;</code>\n       */\n      public java.lang.String getMediaId() {\n        java.lang.Object ref = mediaId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          mediaId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string media_id = 5;</code>\n       */\n      public com.google.protobuf.ByteString\n          getMediaIdBytes() {\n        java.lang.Object ref = mediaId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          mediaId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string media_id = 5;</code>\n       */\n      public Builder setMediaId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        mediaId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string media_id = 5;</code>\n       */\n      public Builder clearMediaId() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        mediaId_ = getDefaultInstance().getMediaId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string media_id = 5;</code>\n       */\n      public Builder setMediaIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        mediaId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string article_id = 6;\n      private java.lang.Object articleId_ = \"\";\n      /**\n       * <code>optional string article_id = 6;</code>\n       */\n      public boolean hasArticleId() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional string article_id = 6;</code>\n       */\n      public java.lang.String getArticleId() {\n        java.lang.Object ref = articleId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          articleId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string article_id = 6;</code>\n       */\n      public com.google.protobuf.ByteString\n          getArticleIdBytes() {\n        java.lang.Object ref = articleId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          articleId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string article_id = 6;</code>\n       */\n      public Builder setArticleId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        articleId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string article_id = 6;</code>\n       */\n      public Builder clearArticleId() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        articleId_ = getDefaultInstance().getArticleId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string article_id = 6;</code>\n       */\n      public Builder setArticleIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        articleId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string app_id = 7;\n      private java.lang.Object appId_ = \"\";\n      /**\n       * <code>optional string app_id = 7;</code>\n       */\n      public boolean hasAppId() {\n        return ((bitField0_ & 0x00000040) == 0x00000040);\n      }\n      /**\n       * <code>optional string app_id = 7;</code>\n       */\n      public java.lang.String getAppId() {\n        java.lang.Object ref = appId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          appId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string app_id = 7;</code>\n       */\n      public com.google.protobuf.ByteString\n          getAppIdBytes() {\n        java.lang.Object ref = appId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          appId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string app_id = 7;</code>\n       */\n      public Builder setAppId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        appId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string app_id = 7;</code>\n       */\n      public Builder clearAppId() {\n        bitField0_ = (bitField0_ & ~0x00000040);\n        appId_ = getDefaultInstance().getAppId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string app_id = 7;</code>\n       */\n      public Builder setAppIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        appId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string app_page = 8;\n      private java.lang.Object appPage_ = \"\";\n      /**\n       * <code>optional string app_page = 8;</code>\n       */\n      public boolean hasAppPage() {\n        return ((bitField0_ & 0x00000080) == 0x00000080);\n      }\n      /**\n       * <code>optional string app_page = 8;</code>\n       */\n      public java.lang.String getAppPage() {\n        java.lang.Object ref = appPage_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          appPage_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string app_page = 8;</code>\n       */\n      public com.google.protobuf.ByteString\n          getAppPageBytes() {\n        java.lang.Object ref = appPage_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          appPage_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string app_page = 8;</code>\n       */\n      public Builder setAppPage(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000080;\n        appPage_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string app_page = 8;</code>\n       */\n      public Builder clearAppPage() {\n        bitField0_ = (bitField0_ & ~0x00000080);\n        appPage_ = getDefaultInstance().getAppPage();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string app_page = 8;</code>\n       */\n      public Builder setAppPageBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000080;\n        appPage_ = value;\n        onChanged();\n        return this;\n      }\n\n      // repeated .ChannelMenu sub_menu = 9;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> subMenu_ =\n        java.util.Collections.emptyList();\n      private void ensureSubMenuIsMutable() {\n        if (!((bitField0_ & 0x00000100) == 0x00000100)) {\n          subMenu_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.ChannelMenu>(subMenu_);\n          bitField0_ |= 0x00000100;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.ChannelMenu, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder, cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> subMenuBuilder_;\n\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> getSubMenuList() {\n        if (subMenuBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(subMenu_);\n        } else {\n          return subMenuBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public int getSubMenuCount() {\n        if (subMenuBuilder_ == null) {\n          return subMenu_.size();\n        } else {\n          return subMenuBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu getSubMenu(int index) {\n        if (subMenuBuilder_ == null) {\n          return subMenu_.get(index);\n        } else {\n          return subMenuBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public Builder setSubMenu(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelMenu value) {\n        if (subMenuBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureSubMenuIsMutable();\n          subMenu_.set(index, value);\n          onChanged();\n        } else {\n          subMenuBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public Builder setSubMenu(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder builderForValue) {\n        if (subMenuBuilder_ == null) {\n          ensureSubMenuIsMutable();\n          subMenu_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          subMenuBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public Builder addSubMenu(cn.wildfirechat.proto.WFCMessage.ChannelMenu value) {\n        if (subMenuBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureSubMenuIsMutable();\n          subMenu_.add(value);\n          onChanged();\n        } else {\n          subMenuBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public Builder addSubMenu(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelMenu value) {\n        if (subMenuBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureSubMenuIsMutable();\n          subMenu_.add(index, value);\n          onChanged();\n        } else {\n          subMenuBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public Builder addSubMenu(\n          cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder builderForValue) {\n        if (subMenuBuilder_ == null) {\n          ensureSubMenuIsMutable();\n          subMenu_.add(builderForValue.build());\n          onChanged();\n        } else {\n          subMenuBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public Builder addSubMenu(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder builderForValue) {\n        if (subMenuBuilder_ == null) {\n          ensureSubMenuIsMutable();\n          subMenu_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          subMenuBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public Builder addAllSubMenu(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.ChannelMenu> values) {\n        if (subMenuBuilder_ == null) {\n          ensureSubMenuIsMutable();\n          super.addAll(values, subMenu_);\n          onChanged();\n        } else {\n          subMenuBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public Builder clearSubMenu() {\n        if (subMenuBuilder_ == null) {\n          subMenu_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000100);\n          onChanged();\n        } else {\n          subMenuBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public Builder removeSubMenu(int index) {\n        if (subMenuBuilder_ == null) {\n          ensureSubMenuIsMutable();\n          subMenu_.remove(index);\n          onChanged();\n        } else {\n          subMenuBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder getSubMenuBuilder(\n          int index) {\n        return getSubMenuFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder getSubMenuOrBuilder(\n          int index) {\n        if (subMenuBuilder_ == null) {\n          return subMenu_.get(index);  } else {\n          return subMenuBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> \n           getSubMenuOrBuilderList() {\n        if (subMenuBuilder_ != null) {\n          return subMenuBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(subMenu_);\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder addSubMenuBuilder() {\n        return getSubMenuFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.ChannelMenu.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder addSubMenuBuilder(\n          int index) {\n        return getSubMenuFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.ChannelMenu.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .ChannelMenu sub_menu = 9;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder> \n           getSubMenuBuilderList() {\n        return getSubMenuFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.ChannelMenu, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder, cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> \n          getSubMenuFieldBuilder() {\n        if (subMenuBuilder_ == null) {\n          subMenuBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.ChannelMenu, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder, cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder>(\n                  subMenu_,\n                  ((bitField0_ & 0x00000100) == 0x00000100),\n                  getParentForChildren(),\n                  isClean());\n          subMenu_ = null;\n        }\n        return subMenuBuilder_;\n      }\n\n      // optional string menu_id = 10;\n      private java.lang.Object menuId_ = \"\";\n      /**\n       * <code>optional string menu_id = 10;</code>\n       */\n      public boolean hasMenuId() {\n        return ((bitField0_ & 0x00000200) == 0x00000200);\n      }\n      /**\n       * <code>optional string menu_id = 10;</code>\n       */\n      public java.lang.String getMenuId() {\n        java.lang.Object ref = menuId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          menuId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string menu_id = 10;</code>\n       */\n      public com.google.protobuf.ByteString\n          getMenuIdBytes() {\n        java.lang.Object ref = menuId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          menuId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string menu_id = 10;</code>\n       */\n      public Builder setMenuId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000200;\n        menuId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string menu_id = 10;</code>\n       */\n      public Builder clearMenuId() {\n        bitField0_ = (bitField0_ & ~0x00000200);\n        menuId_ = getDefaultInstance().getMenuId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string menu_id = 10;</code>\n       */\n      public Builder setMenuIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000200;\n        menuId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string extra = 11;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 11;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000400) == 0x00000400);\n      }\n      /**\n       * <code>optional string extra = 11;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 11;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 11;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000400;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 11;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000400);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 11;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000400;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ChannelMenu)\n    }\n\n    static {\n      defaultInstance = new ChannelMenu(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ChannelMenu)\n  }\n\n  public interface ChannelMenuListOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .ChannelMenu menu = 1;\n    /**\n     * <code>repeated .ChannelMenu menu = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> \n        getMenuList();\n    /**\n     * <code>repeated .ChannelMenu menu = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.ChannelMenu getMenu(int index);\n    /**\n     * <code>repeated .ChannelMenu menu = 1;</code>\n     */\n    int getMenuCount();\n    /**\n     * <code>repeated .ChannelMenu menu = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> \n        getMenuOrBuilderList();\n    /**\n     * <code>repeated .ChannelMenu menu = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder getMenuOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code ChannelMenuList}\n   */\n  public static final class ChannelMenuList extends\n      com.google.protobuf.GeneratedMessage\n      implements ChannelMenuListOrBuilder {\n    // Use ChannelMenuList.newBuilder() to construct.\n    private ChannelMenuList(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ChannelMenuList(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ChannelMenuList defaultInstance;\n    public static ChannelMenuList getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ChannelMenuList getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ChannelMenuList(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                menu_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.ChannelMenu>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              menu_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.ChannelMenu.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          menu_ = java.util.Collections.unmodifiableList(menu_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelMenuList_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelMenuList_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ChannelMenuList.class, cn.wildfirechat.proto.WFCMessage.ChannelMenuList.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ChannelMenuList> PARSER =\n        new com.google.protobuf.AbstractParser<ChannelMenuList>() {\n      public ChannelMenuList parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ChannelMenuList(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ChannelMenuList> getParserForType() {\n      return PARSER;\n    }\n\n    // repeated .ChannelMenu menu = 1;\n    public static final int MENU_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> menu_;\n    /**\n     * <code>repeated .ChannelMenu menu = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> getMenuList() {\n      return menu_;\n    }\n    /**\n     * <code>repeated .ChannelMenu menu = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> \n        getMenuOrBuilderList() {\n      return menu_;\n    }\n    /**\n     * <code>repeated .ChannelMenu menu = 1;</code>\n     */\n    public int getMenuCount() {\n      return menu_.size();\n    }\n    /**\n     * <code>repeated .ChannelMenu menu = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.ChannelMenu getMenu(int index) {\n      return menu_.get(index);\n    }\n    /**\n     * <code>repeated .ChannelMenu menu = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder getMenuOrBuilder(\n        int index) {\n      return menu_.get(index);\n    }\n\n    private void initFields() {\n      menu_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      for (int i = 0; i < getMenuCount(); i++) {\n        if (!getMenu(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < menu_.size(); i++) {\n        output.writeMessage(1, menu_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < menu_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, menu_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenuList parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenuList parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenuList parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenuList parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenuList parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenuList parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenuList parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenuList parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenuList parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelMenuList parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ChannelMenuList prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ChannelMenuList}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ChannelMenuListOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelMenuList_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelMenuList_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ChannelMenuList.class, cn.wildfirechat.proto.WFCMessage.ChannelMenuList.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ChannelMenuList.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getMenuFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (menuBuilder_ == null) {\n          menu_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          menuBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelMenuList_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenuList getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ChannelMenuList.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenuList build() {\n        cn.wildfirechat.proto.WFCMessage.ChannelMenuList result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenuList buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ChannelMenuList result = new cn.wildfirechat.proto.WFCMessage.ChannelMenuList(this);\n        int from_bitField0_ = bitField0_;\n        if (menuBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            menu_ = java.util.Collections.unmodifiableList(menu_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.menu_ = menu_;\n        } else {\n          result.menu_ = menuBuilder_.build();\n        }\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ChannelMenuList) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ChannelMenuList)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ChannelMenuList other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ChannelMenuList.getDefaultInstance()) return this;\n        if (menuBuilder_ == null) {\n          if (!other.menu_.isEmpty()) {\n            if (menu_.isEmpty()) {\n              menu_ = other.menu_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureMenuIsMutable();\n              menu_.addAll(other.menu_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.menu_.isEmpty()) {\n            if (menuBuilder_.isEmpty()) {\n              menuBuilder_.dispose();\n              menuBuilder_ = null;\n              menu_ = other.menu_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              menuBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getMenuFieldBuilder() : null;\n            } else {\n              menuBuilder_.addAllMessages(other.menu_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        for (int i = 0; i < getMenuCount(); i++) {\n          if (!getMenu(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ChannelMenuList parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ChannelMenuList) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .ChannelMenu menu = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> menu_ =\n        java.util.Collections.emptyList();\n      private void ensureMenuIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          menu_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.ChannelMenu>(menu_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.ChannelMenu, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder, cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> menuBuilder_;\n\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> getMenuList() {\n        if (menuBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(menu_);\n        } else {\n          return menuBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public int getMenuCount() {\n        if (menuBuilder_ == null) {\n          return menu_.size();\n        } else {\n          return menuBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu getMenu(int index) {\n        if (menuBuilder_ == null) {\n          return menu_.get(index);\n        } else {\n          return menuBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public Builder setMenu(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelMenu value) {\n        if (menuBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMenuIsMutable();\n          menu_.set(index, value);\n          onChanged();\n        } else {\n          menuBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public Builder setMenu(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder builderForValue) {\n        if (menuBuilder_ == null) {\n          ensureMenuIsMutable();\n          menu_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          menuBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public Builder addMenu(cn.wildfirechat.proto.WFCMessage.ChannelMenu value) {\n        if (menuBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMenuIsMutable();\n          menu_.add(value);\n          onChanged();\n        } else {\n          menuBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public Builder addMenu(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelMenu value) {\n        if (menuBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMenuIsMutable();\n          menu_.add(index, value);\n          onChanged();\n        } else {\n          menuBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public Builder addMenu(\n          cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder builderForValue) {\n        if (menuBuilder_ == null) {\n          ensureMenuIsMutable();\n          menu_.add(builderForValue.build());\n          onChanged();\n        } else {\n          menuBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public Builder addMenu(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder builderForValue) {\n        if (menuBuilder_ == null) {\n          ensureMenuIsMutable();\n          menu_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          menuBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public Builder addAllMenu(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.ChannelMenu> values) {\n        if (menuBuilder_ == null) {\n          ensureMenuIsMutable();\n          super.addAll(values, menu_);\n          onChanged();\n        } else {\n          menuBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public Builder clearMenu() {\n        if (menuBuilder_ == null) {\n          menu_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          menuBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public Builder removeMenu(int index) {\n        if (menuBuilder_ == null) {\n          ensureMenuIsMutable();\n          menu_.remove(index);\n          onChanged();\n        } else {\n          menuBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder getMenuBuilder(\n          int index) {\n        return getMenuFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder getMenuOrBuilder(\n          int index) {\n        if (menuBuilder_ == null) {\n          return menu_.get(index);  } else {\n          return menuBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> \n           getMenuOrBuilderList() {\n        if (menuBuilder_ != null) {\n          return menuBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(menu_);\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder addMenuBuilder() {\n        return getMenuFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.ChannelMenu.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder addMenuBuilder(\n          int index) {\n        return getMenuFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.ChannelMenu.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder> \n           getMenuBuilderList() {\n        return getMenuFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.ChannelMenu, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder, cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> \n          getMenuFieldBuilder() {\n        if (menuBuilder_ == null) {\n          menuBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.ChannelMenu, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder, cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder>(\n                  menu_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          menu_ = null;\n        }\n        return menuBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ChannelMenuList)\n    }\n\n    static {\n      defaultInstance = new ChannelMenuList(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ChannelMenuList)\n  }\n\n  public interface ChannelInfoOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // optional string target_id = 1;\n    /**\n     * <code>optional string target_id = 1;</code>\n     */\n    boolean hasTargetId();\n    /**\n     * <code>optional string target_id = 1;</code>\n     */\n    java.lang.String getTargetId();\n    /**\n     * <code>optional string target_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getTargetIdBytes();\n\n    // required string name = 2;\n    /**\n     * <code>required string name = 2;</code>\n     */\n    boolean hasName();\n    /**\n     * <code>required string name = 2;</code>\n     */\n    java.lang.String getName();\n    /**\n     * <code>required string name = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getNameBytes();\n\n    // optional string portrait = 3;\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    boolean hasPortrait();\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    java.lang.String getPortrait();\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getPortraitBytes();\n\n    // optional string owner = 4;\n    /**\n     * <code>optional string owner = 4;</code>\n     */\n    boolean hasOwner();\n    /**\n     * <code>optional string owner = 4;</code>\n     */\n    java.lang.String getOwner();\n    /**\n     * <code>optional string owner = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getOwnerBytes();\n\n    // optional int32 status = 5;\n    /**\n     * <code>optional int32 status = 5;</code>\n     *\n     * <pre>\n     *0, public; 1, private; 2 closed;\n     * </pre>\n     */\n    boolean hasStatus();\n    /**\n     * <code>optional int32 status = 5;</code>\n     *\n     * <pre>\n     *0, public; 1, private; 2 closed;\n     * </pre>\n     */\n    int getStatus();\n\n    // optional string desc = 6;\n    /**\n     * <code>optional string desc = 6;</code>\n     */\n    boolean hasDesc();\n    /**\n     * <code>optional string desc = 6;</code>\n     */\n    java.lang.String getDesc();\n    /**\n     * <code>optional string desc = 6;</code>\n     */\n    com.google.protobuf.ByteString\n        getDescBytes();\n\n    // optional string extra = 7;\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n\n    // optional int64 update_dt = 8;\n    /**\n     * <code>optional int64 update_dt = 8;</code>\n     */\n    boolean hasUpdateDt();\n    /**\n     * <code>optional int64 update_dt = 8;</code>\n     */\n    long getUpdateDt();\n\n    // optional string secret = 9;\n    /**\n     * <code>optional string secret = 9;</code>\n     */\n    boolean hasSecret();\n    /**\n     * <code>optional string secret = 9;</code>\n     */\n    java.lang.String getSecret();\n    /**\n     * <code>optional string secret = 9;</code>\n     */\n    com.google.protobuf.ByteString\n        getSecretBytes();\n\n    // optional string callback = 10;\n    /**\n     * <code>optional string callback = 10;</code>\n     */\n    boolean hasCallback();\n    /**\n     * <code>optional string callback = 10;</code>\n     */\n    java.lang.String getCallback();\n    /**\n     * <code>optional string callback = 10;</code>\n     */\n    com.google.protobuf.ByteString\n        getCallbackBytes();\n\n    // optional int32 automatic = 11;\n    /**\n     * <code>optional int32 automatic = 11;</code>\n     */\n    boolean hasAutomatic();\n    /**\n     * <code>optional int32 automatic = 11;</code>\n     */\n    int getAutomatic();\n\n    // repeated .ChannelMenu menu = 12;\n    /**\n     * <code>repeated .ChannelMenu menu = 12;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> \n        getMenuList();\n    /**\n     * <code>repeated .ChannelMenu menu = 12;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.ChannelMenu getMenu(int index);\n    /**\n     * <code>repeated .ChannelMenu menu = 12;</code>\n     */\n    int getMenuCount();\n    /**\n     * <code>repeated .ChannelMenu menu = 12;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> \n        getMenuOrBuilderList();\n    /**\n     * <code>repeated .ChannelMenu menu = 12;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder getMenuOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code ChannelInfo}\n   */\n  public static final class ChannelInfo extends\n      com.google.protobuf.GeneratedMessage\n      implements ChannelInfoOrBuilder {\n    // Use ChannelInfo.newBuilder() to construct.\n    private ChannelInfo(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ChannelInfo(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ChannelInfo defaultInstance;\n    public static ChannelInfo getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ChannelInfo getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ChannelInfo(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              targetId_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              name_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              portrait_ = input.readBytes();\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000008;\n              owner_ = input.readBytes();\n              break;\n            }\n            case 40: {\n              bitField0_ |= 0x00000010;\n              status_ = input.readInt32();\n              break;\n            }\n            case 50: {\n              bitField0_ |= 0x00000020;\n              desc_ = input.readBytes();\n              break;\n            }\n            case 58: {\n              bitField0_ |= 0x00000040;\n              extra_ = input.readBytes();\n              break;\n            }\n            case 64: {\n              bitField0_ |= 0x00000080;\n              updateDt_ = input.readInt64();\n              break;\n            }\n            case 74: {\n              bitField0_ |= 0x00000100;\n              secret_ = input.readBytes();\n              break;\n            }\n            case 82: {\n              bitField0_ |= 0x00000200;\n              callback_ = input.readBytes();\n              break;\n            }\n            case 88: {\n              bitField0_ |= 0x00000400;\n              automatic_ = input.readInt32();\n              break;\n            }\n            case 98: {\n              if (!((mutable_bitField0_ & 0x00000800) == 0x00000800)) {\n                menu_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.ChannelMenu>();\n                mutable_bitField0_ |= 0x00000800;\n              }\n              menu_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.ChannelMenu.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000800) == 0x00000800)) {\n          menu_ = java.util.Collections.unmodifiableList(menu_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelInfo_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelInfo_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ChannelInfo.class, cn.wildfirechat.proto.WFCMessage.ChannelInfo.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ChannelInfo> PARSER =\n        new com.google.protobuf.AbstractParser<ChannelInfo>() {\n      public ChannelInfo parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ChannelInfo(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ChannelInfo> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // optional string target_id = 1;\n    public static final int TARGET_ID_FIELD_NUMBER = 1;\n    private java.lang.Object targetId_;\n    /**\n     * <code>optional string target_id = 1;</code>\n     */\n    public boolean hasTargetId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional string target_id = 1;</code>\n     */\n    public java.lang.String getTargetId() {\n      java.lang.Object ref = targetId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          targetId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string target_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTargetIdBytes() {\n      java.lang.Object ref = targetId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        targetId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string name = 2;\n    public static final int NAME_FIELD_NUMBER = 2;\n    private java.lang.Object name_;\n    /**\n     * <code>required string name = 2;</code>\n     */\n    public boolean hasName() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string name = 2;</code>\n     */\n    public java.lang.String getName() {\n      java.lang.Object ref = name_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          name_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string name = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getNameBytes() {\n      java.lang.Object ref = name_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        name_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string portrait = 3;\n    public static final int PORTRAIT_FIELD_NUMBER = 3;\n    private java.lang.Object portrait_;\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    public boolean hasPortrait() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    public java.lang.String getPortrait() {\n      java.lang.Object ref = portrait_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          portrait_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getPortraitBytes() {\n      java.lang.Object ref = portrait_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        portrait_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string owner = 4;\n    public static final int OWNER_FIELD_NUMBER = 4;\n    private java.lang.Object owner_;\n    /**\n     * <code>optional string owner = 4;</code>\n     */\n    public boolean hasOwner() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional string owner = 4;</code>\n     */\n    public java.lang.String getOwner() {\n      java.lang.Object ref = owner_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          owner_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string owner = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getOwnerBytes() {\n      java.lang.Object ref = owner_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        owner_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 status = 5;\n    public static final int STATUS_FIELD_NUMBER = 5;\n    private int status_;\n    /**\n     * <code>optional int32 status = 5;</code>\n     *\n     * <pre>\n     *0, public; 1, private; 2 closed;\n     * </pre>\n     */\n    public boolean hasStatus() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional int32 status = 5;</code>\n     *\n     * <pre>\n     *0, public; 1, private; 2 closed;\n     * </pre>\n     */\n    public int getStatus() {\n      return status_;\n    }\n\n    // optional string desc = 6;\n    public static final int DESC_FIELD_NUMBER = 6;\n    private java.lang.Object desc_;\n    /**\n     * <code>optional string desc = 6;</code>\n     */\n    public boolean hasDesc() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional string desc = 6;</code>\n     */\n    public java.lang.String getDesc() {\n      java.lang.Object ref = desc_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          desc_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string desc = 6;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDescBytes() {\n      java.lang.Object ref = desc_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        desc_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string extra = 7;\n    public static final int EXTRA_FIELD_NUMBER = 7;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000040) == 0x00000040);\n    }\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int64 update_dt = 8;\n    public static final int UPDATE_DT_FIELD_NUMBER = 8;\n    private long updateDt_;\n    /**\n     * <code>optional int64 update_dt = 8;</code>\n     */\n    public boolean hasUpdateDt() {\n      return ((bitField0_ & 0x00000080) == 0x00000080);\n    }\n    /**\n     * <code>optional int64 update_dt = 8;</code>\n     */\n    public long getUpdateDt() {\n      return updateDt_;\n    }\n\n    // optional string secret = 9;\n    public static final int SECRET_FIELD_NUMBER = 9;\n    private java.lang.Object secret_;\n    /**\n     * <code>optional string secret = 9;</code>\n     */\n    public boolean hasSecret() {\n      return ((bitField0_ & 0x00000100) == 0x00000100);\n    }\n    /**\n     * <code>optional string secret = 9;</code>\n     */\n    public java.lang.String getSecret() {\n      java.lang.Object ref = secret_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          secret_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string secret = 9;</code>\n     */\n    public com.google.protobuf.ByteString\n        getSecretBytes() {\n      java.lang.Object ref = secret_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        secret_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string callback = 10;\n    public static final int CALLBACK_FIELD_NUMBER = 10;\n    private java.lang.Object callback_;\n    /**\n     * <code>optional string callback = 10;</code>\n     */\n    public boolean hasCallback() {\n      return ((bitField0_ & 0x00000200) == 0x00000200);\n    }\n    /**\n     * <code>optional string callback = 10;</code>\n     */\n    public java.lang.String getCallback() {\n      java.lang.Object ref = callback_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          callback_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string callback = 10;</code>\n     */\n    public com.google.protobuf.ByteString\n        getCallbackBytes() {\n      java.lang.Object ref = callback_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        callback_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 automatic = 11;\n    public static final int AUTOMATIC_FIELD_NUMBER = 11;\n    private int automatic_;\n    /**\n     * <code>optional int32 automatic = 11;</code>\n     */\n    public boolean hasAutomatic() {\n      return ((bitField0_ & 0x00000400) == 0x00000400);\n    }\n    /**\n     * <code>optional int32 automatic = 11;</code>\n     */\n    public int getAutomatic() {\n      return automatic_;\n    }\n\n    // repeated .ChannelMenu menu = 12;\n    public static final int MENU_FIELD_NUMBER = 12;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> menu_;\n    /**\n     * <code>repeated .ChannelMenu menu = 12;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> getMenuList() {\n      return menu_;\n    }\n    /**\n     * <code>repeated .ChannelMenu menu = 12;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> \n        getMenuOrBuilderList() {\n      return menu_;\n    }\n    /**\n     * <code>repeated .ChannelMenu menu = 12;</code>\n     */\n    public int getMenuCount() {\n      return menu_.size();\n    }\n    /**\n     * <code>repeated .ChannelMenu menu = 12;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.ChannelMenu getMenu(int index) {\n      return menu_.get(index);\n    }\n    /**\n     * <code>repeated .ChannelMenu menu = 12;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder getMenuOrBuilder(\n        int index) {\n      return menu_.get(index);\n    }\n\n    private void initFields() {\n      targetId_ = \"\";\n      name_ = \"\";\n      portrait_ = \"\";\n      owner_ = \"\";\n      status_ = 0;\n      desc_ = \"\";\n      extra_ = \"\";\n      updateDt_ = 0L;\n      secret_ = \"\";\n      callback_ = \"\";\n      automatic_ = 0;\n      menu_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasName()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      for (int i = 0; i < getMenuCount(); i++) {\n        if (!getMenu(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getTargetIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getNameBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getPortraitBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(4, getOwnerBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeInt32(5, status_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeBytes(6, getDescBytes());\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        output.writeBytes(7, getExtraBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        output.writeInt64(8, updateDt_);\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        output.writeBytes(9, getSecretBytes());\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        output.writeBytes(10, getCallbackBytes());\n      }\n      if (((bitField0_ & 0x00000400) == 0x00000400)) {\n        output.writeInt32(11, automatic_);\n      }\n      for (int i = 0; i < menu_.size(); i++) {\n        output.writeMessage(12, menu_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getTargetIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getNameBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getPortraitBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, getOwnerBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(5, status_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(6, getDescBytes());\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(7, getExtraBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(8, updateDt_);\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(9, getSecretBytes());\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(10, getCallbackBytes());\n      }\n      if (((bitField0_ & 0x00000400) == 0x00000400)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(11, automatic_);\n      }\n      for (int i = 0; i < menu_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(12, menu_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ChannelInfo parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelInfo parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelInfo parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelInfo parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelInfo parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelInfo parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelInfo parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelInfo parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelInfo parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChannelInfo parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ChannelInfo prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ChannelInfo}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ChannelInfoOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelInfo_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelInfo_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ChannelInfo.class, cn.wildfirechat.proto.WFCMessage.ChannelInfo.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ChannelInfo.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getMenuFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        targetId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        name_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        portrait_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        owner_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        status_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000010);\n        desc_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000020);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000040);\n        updateDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000080);\n        secret_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000100);\n        callback_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000200);\n        automatic_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000400);\n        if (menuBuilder_ == null) {\n          menu_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000800);\n        } else {\n          menuBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChannelInfo_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChannelInfo getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ChannelInfo.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChannelInfo build() {\n        cn.wildfirechat.proto.WFCMessage.ChannelInfo result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChannelInfo buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ChannelInfo result = new cn.wildfirechat.proto.WFCMessage.ChannelInfo(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.targetId_ = targetId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.name_ = name_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.portrait_ = portrait_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.owner_ = owner_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.status_ = status_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.desc_ = desc_;\n        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {\n          to_bitField0_ |= 0x00000040;\n        }\n        result.extra_ = extra_;\n        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {\n          to_bitField0_ |= 0x00000080;\n        }\n        result.updateDt_ = updateDt_;\n        if (((from_bitField0_ & 0x00000100) == 0x00000100)) {\n          to_bitField0_ |= 0x00000100;\n        }\n        result.secret_ = secret_;\n        if (((from_bitField0_ & 0x00000200) == 0x00000200)) {\n          to_bitField0_ |= 0x00000200;\n        }\n        result.callback_ = callback_;\n        if (((from_bitField0_ & 0x00000400) == 0x00000400)) {\n          to_bitField0_ |= 0x00000400;\n        }\n        result.automatic_ = automatic_;\n        if (menuBuilder_ == null) {\n          if (((bitField0_ & 0x00000800) == 0x00000800)) {\n            menu_ = java.util.Collections.unmodifiableList(menu_);\n            bitField0_ = (bitField0_ & ~0x00000800);\n          }\n          result.menu_ = menu_;\n        } else {\n          result.menu_ = menuBuilder_.build();\n        }\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ChannelInfo) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ChannelInfo)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ChannelInfo other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ChannelInfo.getDefaultInstance()) return this;\n        if (other.hasTargetId()) {\n          bitField0_ |= 0x00000001;\n          targetId_ = other.targetId_;\n          onChanged();\n        }\n        if (other.hasName()) {\n          bitField0_ |= 0x00000002;\n          name_ = other.name_;\n          onChanged();\n        }\n        if (other.hasPortrait()) {\n          bitField0_ |= 0x00000004;\n          portrait_ = other.portrait_;\n          onChanged();\n        }\n        if (other.hasOwner()) {\n          bitField0_ |= 0x00000008;\n          owner_ = other.owner_;\n          onChanged();\n        }\n        if (other.hasStatus()) {\n          setStatus(other.getStatus());\n        }\n        if (other.hasDesc()) {\n          bitField0_ |= 0x00000020;\n          desc_ = other.desc_;\n          onChanged();\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000040;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        if (other.hasUpdateDt()) {\n          setUpdateDt(other.getUpdateDt());\n        }\n        if (other.hasSecret()) {\n          bitField0_ |= 0x00000100;\n          secret_ = other.secret_;\n          onChanged();\n        }\n        if (other.hasCallback()) {\n          bitField0_ |= 0x00000200;\n          callback_ = other.callback_;\n          onChanged();\n        }\n        if (other.hasAutomatic()) {\n          setAutomatic(other.getAutomatic());\n        }\n        if (menuBuilder_ == null) {\n          if (!other.menu_.isEmpty()) {\n            if (menu_.isEmpty()) {\n              menu_ = other.menu_;\n              bitField0_ = (bitField0_ & ~0x00000800);\n            } else {\n              ensureMenuIsMutable();\n              menu_.addAll(other.menu_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.menu_.isEmpty()) {\n            if (menuBuilder_.isEmpty()) {\n              menuBuilder_.dispose();\n              menuBuilder_ = null;\n              menu_ = other.menu_;\n              bitField0_ = (bitField0_ & ~0x00000800);\n              menuBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getMenuFieldBuilder() : null;\n            } else {\n              menuBuilder_.addAllMessages(other.menu_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasName()) {\n          \n          return false;\n        }\n        for (int i = 0; i < getMenuCount(); i++) {\n          if (!getMenu(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ChannelInfo parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ChannelInfo) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // optional string target_id = 1;\n      private java.lang.Object targetId_ = \"\";\n      /**\n       * <code>optional string target_id = 1;</code>\n       */\n      public boolean hasTargetId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional string target_id = 1;</code>\n       */\n      public java.lang.String getTargetId() {\n        java.lang.Object ref = targetId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          targetId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string target_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTargetIdBytes() {\n        java.lang.Object ref = targetId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          targetId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string target_id = 1;</code>\n       */\n      public Builder setTargetId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        targetId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string target_id = 1;</code>\n       */\n      public Builder clearTargetId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        targetId_ = getDefaultInstance().getTargetId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string target_id = 1;</code>\n       */\n      public Builder setTargetIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        targetId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string name = 2;\n      private java.lang.Object name_ = \"\";\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public boolean hasName() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public java.lang.String getName() {\n        java.lang.Object ref = name_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          name_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getNameBytes() {\n        java.lang.Object ref = name_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          name_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public Builder setName(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        name_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public Builder clearName() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        name_ = getDefaultInstance().getName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string name = 2;</code>\n       */\n      public Builder setNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        name_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string portrait = 3;\n      private java.lang.Object portrait_ = \"\";\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public boolean hasPortrait() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public java.lang.String getPortrait() {\n        java.lang.Object ref = portrait_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          portrait_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getPortraitBytes() {\n        java.lang.Object ref = portrait_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          portrait_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public Builder setPortrait(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        portrait_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public Builder clearPortrait() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        portrait_ = getDefaultInstance().getPortrait();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public Builder setPortraitBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        portrait_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string owner = 4;\n      private java.lang.Object owner_ = \"\";\n      /**\n       * <code>optional string owner = 4;</code>\n       */\n      public boolean hasOwner() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional string owner = 4;</code>\n       */\n      public java.lang.String getOwner() {\n        java.lang.Object ref = owner_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          owner_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string owner = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getOwnerBytes() {\n        java.lang.Object ref = owner_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          owner_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string owner = 4;</code>\n       */\n      public Builder setOwner(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        owner_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string owner = 4;</code>\n       */\n      public Builder clearOwner() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        owner_ = getDefaultInstance().getOwner();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string owner = 4;</code>\n       */\n      public Builder setOwnerBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        owner_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 status = 5;\n      private int status_ ;\n      /**\n       * <code>optional int32 status = 5;</code>\n       *\n       * <pre>\n       *0, public; 1, private; 2 closed;\n       * </pre>\n       */\n      public boolean hasStatus() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional int32 status = 5;</code>\n       *\n       * <pre>\n       *0, public; 1, private; 2 closed;\n       * </pre>\n       */\n      public int getStatus() {\n        return status_;\n      }\n      /**\n       * <code>optional int32 status = 5;</code>\n       *\n       * <pre>\n       *0, public; 1, private; 2 closed;\n       * </pre>\n       */\n      public Builder setStatus(int value) {\n        bitField0_ |= 0x00000010;\n        status_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 status = 5;</code>\n       *\n       * <pre>\n       *0, public; 1, private; 2 closed;\n       * </pre>\n       */\n      public Builder clearStatus() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        status_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional string desc = 6;\n      private java.lang.Object desc_ = \"\";\n      /**\n       * <code>optional string desc = 6;</code>\n       */\n      public boolean hasDesc() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional string desc = 6;</code>\n       */\n      public java.lang.String getDesc() {\n        java.lang.Object ref = desc_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          desc_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string desc = 6;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDescBytes() {\n        java.lang.Object ref = desc_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          desc_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string desc = 6;</code>\n       */\n      public Builder setDesc(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        desc_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string desc = 6;</code>\n       */\n      public Builder clearDesc() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        desc_ = getDefaultInstance().getDesc();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string desc = 6;</code>\n       */\n      public Builder setDescBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        desc_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string extra = 7;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000040) == 0x00000040);\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000040);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 update_dt = 8;\n      private long updateDt_ ;\n      /**\n       * <code>optional int64 update_dt = 8;</code>\n       */\n      public boolean hasUpdateDt() {\n        return ((bitField0_ & 0x00000080) == 0x00000080);\n      }\n      /**\n       * <code>optional int64 update_dt = 8;</code>\n       */\n      public long getUpdateDt() {\n        return updateDt_;\n      }\n      /**\n       * <code>optional int64 update_dt = 8;</code>\n       */\n      public Builder setUpdateDt(long value) {\n        bitField0_ |= 0x00000080;\n        updateDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 update_dt = 8;</code>\n       */\n      public Builder clearUpdateDt() {\n        bitField0_ = (bitField0_ & ~0x00000080);\n        updateDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional string secret = 9;\n      private java.lang.Object secret_ = \"\";\n      /**\n       * <code>optional string secret = 9;</code>\n       */\n      public boolean hasSecret() {\n        return ((bitField0_ & 0x00000100) == 0x00000100);\n      }\n      /**\n       * <code>optional string secret = 9;</code>\n       */\n      public java.lang.String getSecret() {\n        java.lang.Object ref = secret_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          secret_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string secret = 9;</code>\n       */\n      public com.google.protobuf.ByteString\n          getSecretBytes() {\n        java.lang.Object ref = secret_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          secret_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string secret = 9;</code>\n       */\n      public Builder setSecret(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000100;\n        secret_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string secret = 9;</code>\n       */\n      public Builder clearSecret() {\n        bitField0_ = (bitField0_ & ~0x00000100);\n        secret_ = getDefaultInstance().getSecret();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string secret = 9;</code>\n       */\n      public Builder setSecretBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000100;\n        secret_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string callback = 10;\n      private java.lang.Object callback_ = \"\";\n      /**\n       * <code>optional string callback = 10;</code>\n       */\n      public boolean hasCallback() {\n        return ((bitField0_ & 0x00000200) == 0x00000200);\n      }\n      /**\n       * <code>optional string callback = 10;</code>\n       */\n      public java.lang.String getCallback() {\n        java.lang.Object ref = callback_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          callback_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string callback = 10;</code>\n       */\n      public com.google.protobuf.ByteString\n          getCallbackBytes() {\n        java.lang.Object ref = callback_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          callback_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string callback = 10;</code>\n       */\n      public Builder setCallback(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000200;\n        callback_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string callback = 10;</code>\n       */\n      public Builder clearCallback() {\n        bitField0_ = (bitField0_ & ~0x00000200);\n        callback_ = getDefaultInstance().getCallback();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string callback = 10;</code>\n       */\n      public Builder setCallbackBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000200;\n        callback_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 automatic = 11;\n      private int automatic_ ;\n      /**\n       * <code>optional int32 automatic = 11;</code>\n       */\n      public boolean hasAutomatic() {\n        return ((bitField0_ & 0x00000400) == 0x00000400);\n      }\n      /**\n       * <code>optional int32 automatic = 11;</code>\n       */\n      public int getAutomatic() {\n        return automatic_;\n      }\n      /**\n       * <code>optional int32 automatic = 11;</code>\n       */\n      public Builder setAutomatic(int value) {\n        bitField0_ |= 0x00000400;\n        automatic_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 automatic = 11;</code>\n       */\n      public Builder clearAutomatic() {\n        bitField0_ = (bitField0_ & ~0x00000400);\n        automatic_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // repeated .ChannelMenu menu = 12;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> menu_ =\n        java.util.Collections.emptyList();\n      private void ensureMenuIsMutable() {\n        if (!((bitField0_ & 0x00000800) == 0x00000800)) {\n          menu_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.ChannelMenu>(menu_);\n          bitField0_ |= 0x00000800;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.ChannelMenu, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder, cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> menuBuilder_;\n\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu> getMenuList() {\n        if (menuBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(menu_);\n        } else {\n          return menuBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public int getMenuCount() {\n        if (menuBuilder_ == null) {\n          return menu_.size();\n        } else {\n          return menuBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu getMenu(int index) {\n        if (menuBuilder_ == null) {\n          return menu_.get(index);\n        } else {\n          return menuBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public Builder setMenu(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelMenu value) {\n        if (menuBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMenuIsMutable();\n          menu_.set(index, value);\n          onChanged();\n        } else {\n          menuBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public Builder setMenu(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder builderForValue) {\n        if (menuBuilder_ == null) {\n          ensureMenuIsMutable();\n          menu_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          menuBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public Builder addMenu(cn.wildfirechat.proto.WFCMessage.ChannelMenu value) {\n        if (menuBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMenuIsMutable();\n          menu_.add(value);\n          onChanged();\n        } else {\n          menuBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public Builder addMenu(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelMenu value) {\n        if (menuBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMenuIsMutable();\n          menu_.add(index, value);\n          onChanged();\n        } else {\n          menuBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public Builder addMenu(\n          cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder builderForValue) {\n        if (menuBuilder_ == null) {\n          ensureMenuIsMutable();\n          menu_.add(builderForValue.build());\n          onChanged();\n        } else {\n          menuBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public Builder addMenu(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder builderForValue) {\n        if (menuBuilder_ == null) {\n          ensureMenuIsMutable();\n          menu_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          menuBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public Builder addAllMenu(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.ChannelMenu> values) {\n        if (menuBuilder_ == null) {\n          ensureMenuIsMutable();\n          super.addAll(values, menu_);\n          onChanged();\n        } else {\n          menuBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public Builder clearMenu() {\n        if (menuBuilder_ == null) {\n          menu_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000800);\n          onChanged();\n        } else {\n          menuBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public Builder removeMenu(int index) {\n        if (menuBuilder_ == null) {\n          ensureMenuIsMutable();\n          menu_.remove(index);\n          onChanged();\n        } else {\n          menuBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder getMenuBuilder(\n          int index) {\n        return getMenuFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder getMenuOrBuilder(\n          int index) {\n        if (menuBuilder_ == null) {\n          return menu_.get(index);  } else {\n          return menuBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> \n           getMenuOrBuilderList() {\n        if (menuBuilder_ != null) {\n          return menuBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(menu_);\n        }\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder addMenuBuilder() {\n        return getMenuFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.ChannelMenu.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder addMenuBuilder(\n          int index) {\n        return getMenuFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.ChannelMenu.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .ChannelMenu menu = 12;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder> \n           getMenuBuilderList() {\n        return getMenuFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.ChannelMenu, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder, cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder> \n          getMenuFieldBuilder() {\n        if (menuBuilder_ == null) {\n          menuBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.ChannelMenu, cn.wildfirechat.proto.WFCMessage.ChannelMenu.Builder, cn.wildfirechat.proto.WFCMessage.ChannelMenuOrBuilder>(\n                  menu_,\n                  ((bitField0_ & 0x00000800) == 0x00000800),\n                  getParentForChildren(),\n                  isClean());\n          menu_ = null;\n        }\n        return menuBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ChannelInfo)\n    }\n\n    static {\n      defaultInstance = new ChannelInfo(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ChannelInfo)\n  }\n\n  public interface ModifyChannelInfoOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string channel_id = 1;\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    boolean hasChannelId();\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    java.lang.String getChannelId();\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getChannelIdBytes();\n\n    // required int32 type = 2;\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    int getType();\n\n    // required string value = 3;\n    /**\n     * <code>required string value = 3;</code>\n     */\n    boolean hasValue();\n    /**\n     * <code>required string value = 3;</code>\n     */\n    java.lang.String getValue();\n    /**\n     * <code>required string value = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getValueBytes();\n  }\n  /**\n   * Protobuf type {@code ModifyChannelInfo}\n   */\n  public static final class ModifyChannelInfo extends\n      com.google.protobuf.GeneratedMessage\n      implements ModifyChannelInfoOrBuilder {\n    // Use ModifyChannelInfo.newBuilder() to construct.\n    private ModifyChannelInfo(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ModifyChannelInfo(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ModifyChannelInfo defaultInstance;\n    public static ModifyChannelInfo getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ModifyChannelInfo getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ModifyChannelInfo(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              channelId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              type_ = input.readInt32();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              value_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyChannelInfo_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyChannelInfo_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo.class, cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ModifyChannelInfo> PARSER =\n        new com.google.protobuf.AbstractParser<ModifyChannelInfo>() {\n      public ModifyChannelInfo parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ModifyChannelInfo(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ModifyChannelInfo> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string channel_id = 1;\n    public static final int CHANNEL_ID_FIELD_NUMBER = 1;\n    private java.lang.Object channelId_;\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public boolean hasChannelId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public java.lang.String getChannelId() {\n      java.lang.Object ref = channelId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          channelId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getChannelIdBytes() {\n      java.lang.Object ref = channelId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        channelId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 type = 2;\n    public static final int TYPE_FIELD_NUMBER = 2;\n    private int type_;\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    // required string value = 3;\n    public static final int VALUE_FIELD_NUMBER = 3;\n    private java.lang.Object value_;\n    /**\n     * <code>required string value = 3;</code>\n     */\n    public boolean hasValue() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required string value = 3;</code>\n     */\n    public java.lang.String getValue() {\n      java.lang.Object ref = value_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          value_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string value = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getValueBytes() {\n      java.lang.Object ref = value_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        value_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      channelId_ = \"\";\n      type_ = 0;\n      value_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasChannelId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasValue()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getChannelIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, type_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getValueBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getChannelIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, type_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getValueBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ModifyChannelInfo}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ModifyChannelInfoOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyChannelInfo_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyChannelInfo_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo.class, cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        channelId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        value_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyChannelInfo_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo build() {\n        cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo result = new cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.channelId_ = channelId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.type_ = type_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.value_ = value_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo.getDefaultInstance()) return this;\n        if (other.hasChannelId()) {\n          bitField0_ |= 0x00000001;\n          channelId_ = other.channelId_;\n          onChanged();\n        }\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        if (other.hasValue()) {\n          bitField0_ |= 0x00000004;\n          value_ = other.value_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasChannelId()) {\n          \n          return false;\n        }\n        if (!hasType()) {\n          \n          return false;\n        }\n        if (!hasValue()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ModifyChannelInfo) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string channel_id = 1;\n      private java.lang.Object channelId_ = \"\";\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public boolean hasChannelId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public java.lang.String getChannelId() {\n        java.lang.Object ref = channelId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          channelId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getChannelIdBytes() {\n        java.lang.Object ref = channelId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          channelId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder setChannelId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        channelId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder clearChannelId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        channelId_ = getDefaultInstance().getChannelId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder setChannelIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        channelId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 type = 2;\n      private int type_ ;\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00000002;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required string value = 3;\n      private java.lang.Object value_ = \"\";\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public boolean hasValue() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public java.lang.String getValue() {\n        java.lang.Object ref = value_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          value_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getValueBytes() {\n        java.lang.Object ref = value_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          value_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public Builder setValue(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public Builder clearValue() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        value_ = getDefaultInstance().getValue();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public Builder setValueBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ModifyChannelInfo)\n    }\n\n    static {\n      defaultInstance = new ModifyChannelInfo(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ModifyChannelInfo)\n  }\n\n  public interface TransferChannelOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string channel_id = 1;\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    boolean hasChannelId();\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    java.lang.String getChannelId();\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getChannelIdBytes();\n\n    // required string new_owner = 2;\n    /**\n     * <code>required string new_owner = 2;</code>\n     */\n    boolean hasNewOwner();\n    /**\n     * <code>required string new_owner = 2;</code>\n     */\n    java.lang.String getNewOwner();\n    /**\n     * <code>required string new_owner = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getNewOwnerBytes();\n  }\n  /**\n   * Protobuf type {@code TransferChannel}\n   */\n  public static final class TransferChannel extends\n      com.google.protobuf.GeneratedMessage\n      implements TransferChannelOrBuilder {\n    // Use TransferChannel.newBuilder() to construct.\n    private TransferChannel(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private TransferChannel(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final TransferChannel defaultInstance;\n    public static TransferChannel getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public TransferChannel getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private TransferChannel(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              channelId_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              newOwner_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_TransferChannel_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_TransferChannel_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.TransferChannel.class, cn.wildfirechat.proto.WFCMessage.TransferChannel.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<TransferChannel> PARSER =\n        new com.google.protobuf.AbstractParser<TransferChannel>() {\n      public TransferChannel parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new TransferChannel(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<TransferChannel> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string channel_id = 1;\n    public static final int CHANNEL_ID_FIELD_NUMBER = 1;\n    private java.lang.Object channelId_;\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public boolean hasChannelId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public java.lang.String getChannelId() {\n      java.lang.Object ref = channelId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          channelId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getChannelIdBytes() {\n      java.lang.Object ref = channelId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        channelId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string new_owner = 2;\n    public static final int NEW_OWNER_FIELD_NUMBER = 2;\n    private java.lang.Object newOwner_;\n    /**\n     * <code>required string new_owner = 2;</code>\n     */\n    public boolean hasNewOwner() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string new_owner = 2;</code>\n     */\n    public java.lang.String getNewOwner() {\n      java.lang.Object ref = newOwner_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          newOwner_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string new_owner = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getNewOwnerBytes() {\n      java.lang.Object ref = newOwner_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        newOwner_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      channelId_ = \"\";\n      newOwner_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasChannelId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasNewOwner()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getChannelIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getNewOwnerBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getChannelIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getNewOwnerBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.TransferChannel parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferChannel parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferChannel parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferChannel parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferChannel parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferChannel parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferChannel parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferChannel parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferChannel parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferChannel parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.TransferChannel prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code TransferChannel}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.TransferChannelOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_TransferChannel_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_TransferChannel_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.TransferChannel.class, cn.wildfirechat.proto.WFCMessage.TransferChannel.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.TransferChannel.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        channelId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        newOwner_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_TransferChannel_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.TransferChannel getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.TransferChannel.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.TransferChannel build() {\n        cn.wildfirechat.proto.WFCMessage.TransferChannel result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.TransferChannel buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.TransferChannel result = new cn.wildfirechat.proto.WFCMessage.TransferChannel(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.channelId_ = channelId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.newOwner_ = newOwner_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.TransferChannel) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.TransferChannel)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.TransferChannel other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.TransferChannel.getDefaultInstance()) return this;\n        if (other.hasChannelId()) {\n          bitField0_ |= 0x00000001;\n          channelId_ = other.channelId_;\n          onChanged();\n        }\n        if (other.hasNewOwner()) {\n          bitField0_ |= 0x00000002;\n          newOwner_ = other.newOwner_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasChannelId()) {\n          \n          return false;\n        }\n        if (!hasNewOwner()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.TransferChannel parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.TransferChannel) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string channel_id = 1;\n      private java.lang.Object channelId_ = \"\";\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public boolean hasChannelId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public java.lang.String getChannelId() {\n        java.lang.Object ref = channelId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          channelId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getChannelIdBytes() {\n        java.lang.Object ref = channelId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          channelId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder setChannelId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        channelId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder clearChannelId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        channelId_ = getDefaultInstance().getChannelId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder setChannelIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        channelId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string new_owner = 2;\n      private java.lang.Object newOwner_ = \"\";\n      /**\n       * <code>required string new_owner = 2;</code>\n       */\n      public boolean hasNewOwner() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string new_owner = 2;</code>\n       */\n      public java.lang.String getNewOwner() {\n        java.lang.Object ref = newOwner_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          newOwner_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string new_owner = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getNewOwnerBytes() {\n        java.lang.Object ref = newOwner_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          newOwner_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string new_owner = 2;</code>\n       */\n      public Builder setNewOwner(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        newOwner_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string new_owner = 2;</code>\n       */\n      public Builder clearNewOwner() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        newOwner_ = getDefaultInstance().getNewOwner();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string new_owner = 2;</code>\n       */\n      public Builder setNewOwnerBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        newOwner_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:TransferChannel)\n    }\n\n    static {\n      defaultInstance = new TransferChannel(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:TransferChannel)\n  }\n\n  public interface PullChannelInfoOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string channel_id = 1;\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    boolean hasChannelId();\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    java.lang.String getChannelId();\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getChannelIdBytes();\n\n    // required int64 head = 2;\n    /**\n     * <code>required int64 head = 2;</code>\n     */\n    boolean hasHead();\n    /**\n     * <code>required int64 head = 2;</code>\n     */\n    long getHead();\n  }\n  /**\n   * Protobuf type {@code PullChannelInfo}\n   */\n  public static final class PullChannelInfo extends\n      com.google.protobuf.GeneratedMessage\n      implements PullChannelInfoOrBuilder {\n    // Use PullChannelInfo.newBuilder() to construct.\n    private PullChannelInfo(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private PullChannelInfo(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final PullChannelInfo defaultInstance;\n    public static PullChannelInfo getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public PullChannelInfo getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private PullChannelInfo(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              channelId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              head_ = input.readInt64();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelInfo_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelInfo_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.PullChannelInfo.class, cn.wildfirechat.proto.WFCMessage.PullChannelInfo.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<PullChannelInfo> PARSER =\n        new com.google.protobuf.AbstractParser<PullChannelInfo>() {\n      public PullChannelInfo parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new PullChannelInfo(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<PullChannelInfo> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string channel_id = 1;\n    public static final int CHANNEL_ID_FIELD_NUMBER = 1;\n    private java.lang.Object channelId_;\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public boolean hasChannelId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public java.lang.String getChannelId() {\n      java.lang.Object ref = channelId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          channelId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getChannelIdBytes() {\n      java.lang.Object ref = channelId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        channelId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int64 head = 2;\n    public static final int HEAD_FIELD_NUMBER = 2;\n    private long head_;\n    /**\n     * <code>required int64 head = 2;</code>\n     */\n    public boolean hasHead() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int64 head = 2;</code>\n     */\n    public long getHead() {\n      return head_;\n    }\n\n    private void initFields() {\n      channelId_ = \"\";\n      head_ = 0L;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasChannelId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasHead()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getChannelIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt64(2, head_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getChannelIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(2, head_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelInfo parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelInfo parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelInfo parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelInfo parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelInfo parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelInfo parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelInfo parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelInfo parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelInfo parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelInfo parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.PullChannelInfo prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code PullChannelInfo}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.PullChannelInfoOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelInfo_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelInfo_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.PullChannelInfo.class, cn.wildfirechat.proto.WFCMessage.PullChannelInfo.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.PullChannelInfo.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        channelId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        head_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelInfo_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullChannelInfo getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.PullChannelInfo.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullChannelInfo build() {\n        cn.wildfirechat.proto.WFCMessage.PullChannelInfo result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullChannelInfo buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.PullChannelInfo result = new cn.wildfirechat.proto.WFCMessage.PullChannelInfo(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.channelId_ = channelId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.head_ = head_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.PullChannelInfo) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.PullChannelInfo)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.PullChannelInfo other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.PullChannelInfo.getDefaultInstance()) return this;\n        if (other.hasChannelId()) {\n          bitField0_ |= 0x00000001;\n          channelId_ = other.channelId_;\n          onChanged();\n        }\n        if (other.hasHead()) {\n          setHead(other.getHead());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasChannelId()) {\n          \n          return false;\n        }\n        if (!hasHead()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.PullChannelInfo parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.PullChannelInfo) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string channel_id = 1;\n      private java.lang.Object channelId_ = \"\";\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public boolean hasChannelId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public java.lang.String getChannelId() {\n        java.lang.Object ref = channelId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          channelId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getChannelIdBytes() {\n        java.lang.Object ref = channelId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          channelId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder setChannelId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        channelId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder clearChannelId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        channelId_ = getDefaultInstance().getChannelId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder setChannelIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        channelId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int64 head = 2;\n      private long head_ ;\n      /**\n       * <code>required int64 head = 2;</code>\n       */\n      public boolean hasHead() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int64 head = 2;</code>\n       */\n      public long getHead() {\n        return head_;\n      }\n      /**\n       * <code>required int64 head = 2;</code>\n       */\n      public Builder setHead(long value) {\n        bitField0_ |= 0x00000002;\n        head_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 head = 2;</code>\n       */\n      public Builder clearHead() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        head_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:PullChannelInfo)\n    }\n\n    static {\n      defaultInstance = new PullChannelInfo(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:PullChannelInfo)\n  }\n\n  public interface PullChannelListenerOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string channel_id = 1;\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    boolean hasChannelId();\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    java.lang.String getChannelId();\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getChannelIdBytes();\n\n    // required int32 offset = 2;\n    /**\n     * <code>required int32 offset = 2;</code>\n     */\n    boolean hasOffset();\n    /**\n     * <code>required int32 offset = 2;</code>\n     */\n    int getOffset();\n\n    // required int32 count = 3;\n    /**\n     * <code>required int32 count = 3;</code>\n     */\n    boolean hasCount();\n    /**\n     * <code>required int32 count = 3;</code>\n     */\n    int getCount();\n  }\n  /**\n   * Protobuf type {@code PullChannelListener}\n   */\n  public static final class PullChannelListener extends\n      com.google.protobuf.GeneratedMessage\n      implements PullChannelListenerOrBuilder {\n    // Use PullChannelListener.newBuilder() to construct.\n    private PullChannelListener(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private PullChannelListener(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final PullChannelListener defaultInstance;\n    public static PullChannelListener getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public PullChannelListener getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private PullChannelListener(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              channelId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              offset_ = input.readInt32();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              count_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelListener_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelListener_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.PullChannelListener.class, cn.wildfirechat.proto.WFCMessage.PullChannelListener.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<PullChannelListener> PARSER =\n        new com.google.protobuf.AbstractParser<PullChannelListener>() {\n      public PullChannelListener parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new PullChannelListener(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<PullChannelListener> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string channel_id = 1;\n    public static final int CHANNEL_ID_FIELD_NUMBER = 1;\n    private java.lang.Object channelId_;\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public boolean hasChannelId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public java.lang.String getChannelId() {\n      java.lang.Object ref = channelId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          channelId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getChannelIdBytes() {\n      java.lang.Object ref = channelId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        channelId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 offset = 2;\n    public static final int OFFSET_FIELD_NUMBER = 2;\n    private int offset_;\n    /**\n     * <code>required int32 offset = 2;</code>\n     */\n    public boolean hasOffset() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 offset = 2;</code>\n     */\n    public int getOffset() {\n      return offset_;\n    }\n\n    // required int32 count = 3;\n    public static final int COUNT_FIELD_NUMBER = 3;\n    private int count_;\n    /**\n     * <code>required int32 count = 3;</code>\n     */\n    public boolean hasCount() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required int32 count = 3;</code>\n     */\n    public int getCount() {\n      return count_;\n    }\n\n    private void initFields() {\n      channelId_ = \"\";\n      offset_ = 0;\n      count_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasChannelId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasOffset()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasCount()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getChannelIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, offset_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt32(3, count_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getChannelIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, offset_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(3, count_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListener parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListener parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListener parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListener parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListener parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListener parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListener parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListener parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListener parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListener parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.PullChannelListener prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code PullChannelListener}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.PullChannelListenerOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelListener_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelListener_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.PullChannelListener.class, cn.wildfirechat.proto.WFCMessage.PullChannelListener.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.PullChannelListener.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        channelId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        offset_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        count_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelListener_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullChannelListener getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.PullChannelListener.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullChannelListener build() {\n        cn.wildfirechat.proto.WFCMessage.PullChannelListener result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullChannelListener buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.PullChannelListener result = new cn.wildfirechat.proto.WFCMessage.PullChannelListener(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.channelId_ = channelId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.offset_ = offset_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.count_ = count_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.PullChannelListener) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.PullChannelListener)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.PullChannelListener other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.PullChannelListener.getDefaultInstance()) return this;\n        if (other.hasChannelId()) {\n          bitField0_ |= 0x00000001;\n          channelId_ = other.channelId_;\n          onChanged();\n        }\n        if (other.hasOffset()) {\n          setOffset(other.getOffset());\n        }\n        if (other.hasCount()) {\n          setCount(other.getCount());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasChannelId()) {\n          \n          return false;\n        }\n        if (!hasOffset()) {\n          \n          return false;\n        }\n        if (!hasCount()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.PullChannelListener parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.PullChannelListener) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string channel_id = 1;\n      private java.lang.Object channelId_ = \"\";\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public boolean hasChannelId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public java.lang.String getChannelId() {\n        java.lang.Object ref = channelId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          channelId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getChannelIdBytes() {\n        java.lang.Object ref = channelId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          channelId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder setChannelId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        channelId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder clearChannelId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        channelId_ = getDefaultInstance().getChannelId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder setChannelIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        channelId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 offset = 2;\n      private int offset_ ;\n      /**\n       * <code>required int32 offset = 2;</code>\n       */\n      public boolean hasOffset() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 offset = 2;</code>\n       */\n      public int getOffset() {\n        return offset_;\n      }\n      /**\n       * <code>required int32 offset = 2;</code>\n       */\n      public Builder setOffset(int value) {\n        bitField0_ |= 0x00000002;\n        offset_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 offset = 2;</code>\n       */\n      public Builder clearOffset() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        offset_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required int32 count = 3;\n      private int count_ ;\n      /**\n       * <code>required int32 count = 3;</code>\n       */\n      public boolean hasCount() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required int32 count = 3;</code>\n       */\n      public int getCount() {\n        return count_;\n      }\n      /**\n       * <code>required int32 count = 3;</code>\n       */\n      public Builder setCount(int value) {\n        bitField0_ |= 0x00000004;\n        count_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 count = 3;</code>\n       */\n      public Builder clearCount() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        count_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:PullChannelListener)\n    }\n\n    static {\n      defaultInstance = new PullChannelListener(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:PullChannelListener)\n  }\n\n  public interface PullChannelListenerResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int32 total_count = 1;\n    /**\n     * <code>required int32 total_count = 1;</code>\n     */\n    boolean hasTotalCount();\n    /**\n     * <code>required int32 total_count = 1;</code>\n     */\n    int getTotalCount();\n\n    // required int32 offset = 2;\n    /**\n     * <code>required int32 offset = 2;</code>\n     */\n    boolean hasOffset();\n    /**\n     * <code>required int32 offset = 2;</code>\n     */\n    int getOffset();\n\n    // repeated string listener = 3;\n    /**\n     * <code>repeated string listener = 3;</code>\n     */\n    java.util.List<java.lang.String>\n    getListenerList();\n    /**\n     * <code>repeated string listener = 3;</code>\n     */\n    int getListenerCount();\n    /**\n     * <code>repeated string listener = 3;</code>\n     */\n    java.lang.String getListener(int index);\n    /**\n     * <code>repeated string listener = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getListenerBytes(int index);\n  }\n  /**\n   * Protobuf type {@code PullChannelListenerResult}\n   */\n  public static final class PullChannelListenerResult extends\n      com.google.protobuf.GeneratedMessage\n      implements PullChannelListenerResultOrBuilder {\n    // Use PullChannelListenerResult.newBuilder() to construct.\n    private PullChannelListenerResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private PullChannelListenerResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final PullChannelListenerResult defaultInstance;\n    public static PullChannelListenerResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public PullChannelListenerResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private PullChannelListenerResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              totalCount_ = input.readInt32();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              offset_ = input.readInt32();\n              break;\n            }\n            case 26: {\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n                listener_ = new com.google.protobuf.LazyStringArrayList();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              listener_.add(input.readBytes());\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n          listener_ = new com.google.protobuf.UnmodifiableLazyStringList(listener_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelListenerResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelListenerResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult.class, cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<PullChannelListenerResult> PARSER =\n        new com.google.protobuf.AbstractParser<PullChannelListenerResult>() {\n      public PullChannelListenerResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new PullChannelListenerResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<PullChannelListenerResult> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int32 total_count = 1;\n    public static final int TOTAL_COUNT_FIELD_NUMBER = 1;\n    private int totalCount_;\n    /**\n     * <code>required int32 total_count = 1;</code>\n     */\n    public boolean hasTotalCount() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int32 total_count = 1;</code>\n     */\n    public int getTotalCount() {\n      return totalCount_;\n    }\n\n    // required int32 offset = 2;\n    public static final int OFFSET_FIELD_NUMBER = 2;\n    private int offset_;\n    /**\n     * <code>required int32 offset = 2;</code>\n     */\n    public boolean hasOffset() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 offset = 2;</code>\n     */\n    public int getOffset() {\n      return offset_;\n    }\n\n    // repeated string listener = 3;\n    public static final int LISTENER_FIELD_NUMBER = 3;\n    private com.google.protobuf.LazyStringList listener_;\n    /**\n     * <code>repeated string listener = 3;</code>\n     */\n    public java.util.List<java.lang.String>\n        getListenerList() {\n      return listener_;\n    }\n    /**\n     * <code>repeated string listener = 3;</code>\n     */\n    public int getListenerCount() {\n      return listener_.size();\n    }\n    /**\n     * <code>repeated string listener = 3;</code>\n     */\n    public java.lang.String getListener(int index) {\n      return listener_.get(index);\n    }\n    /**\n     * <code>repeated string listener = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getListenerBytes(int index) {\n      return listener_.getByteString(index);\n    }\n\n    private void initFields() {\n      totalCount_ = 0;\n      offset_ = 0;\n      listener_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasTotalCount()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasOffset()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, totalCount_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, offset_);\n      }\n      for (int i = 0; i < listener_.size(); i++) {\n        output.writeBytes(3, listener_.getByteString(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, totalCount_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, offset_);\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < listener_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeBytesSizeNoTag(listener_.getByteString(i));\n        }\n        size += dataSize;\n        size += 1 * getListenerList().size();\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code PullChannelListenerResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.PullChannelListenerResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelListenerResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelListenerResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult.class, cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        totalCount_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        offset_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        listener_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullChannelListenerResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult build() {\n        cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult result = new cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.totalCount_ = totalCount_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.offset_ = offset_;\n        if (((bitField0_ & 0x00000004) == 0x00000004)) {\n          listener_ = new com.google.protobuf.UnmodifiableLazyStringList(\n              listener_);\n          bitField0_ = (bitField0_ & ~0x00000004);\n        }\n        result.listener_ = listener_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult.getDefaultInstance()) return this;\n        if (other.hasTotalCount()) {\n          setTotalCount(other.getTotalCount());\n        }\n        if (other.hasOffset()) {\n          setOffset(other.getOffset());\n        }\n        if (!other.listener_.isEmpty()) {\n          if (listener_.isEmpty()) {\n            listener_ = other.listener_;\n            bitField0_ = (bitField0_ & ~0x00000004);\n          } else {\n            ensureListenerIsMutable();\n            listener_.addAll(other.listener_);\n          }\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasTotalCount()) {\n          \n          return false;\n        }\n        if (!hasOffset()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.PullChannelListenerResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int32 total_count = 1;\n      private int totalCount_ ;\n      /**\n       * <code>required int32 total_count = 1;</code>\n       */\n      public boolean hasTotalCount() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int32 total_count = 1;</code>\n       */\n      public int getTotalCount() {\n        return totalCount_;\n      }\n      /**\n       * <code>required int32 total_count = 1;</code>\n       */\n      public Builder setTotalCount(int value) {\n        bitField0_ |= 0x00000001;\n        totalCount_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 total_count = 1;</code>\n       */\n      public Builder clearTotalCount() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        totalCount_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required int32 offset = 2;\n      private int offset_ ;\n      /**\n       * <code>required int32 offset = 2;</code>\n       */\n      public boolean hasOffset() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 offset = 2;</code>\n       */\n      public int getOffset() {\n        return offset_;\n      }\n      /**\n       * <code>required int32 offset = 2;</code>\n       */\n      public Builder setOffset(int value) {\n        bitField0_ |= 0x00000002;\n        offset_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 offset = 2;</code>\n       */\n      public Builder clearOffset() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        offset_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // repeated string listener = 3;\n      private com.google.protobuf.LazyStringList listener_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      private void ensureListenerIsMutable() {\n        if (!((bitField0_ & 0x00000004) == 0x00000004)) {\n          listener_ = new com.google.protobuf.LazyStringArrayList(listener_);\n          bitField0_ |= 0x00000004;\n         }\n      }\n      /**\n       * <code>repeated string listener = 3;</code>\n       */\n      public java.util.List<java.lang.String>\n          getListenerList() {\n        return java.util.Collections.unmodifiableList(listener_);\n      }\n      /**\n       * <code>repeated string listener = 3;</code>\n       */\n      public int getListenerCount() {\n        return listener_.size();\n      }\n      /**\n       * <code>repeated string listener = 3;</code>\n       */\n      public java.lang.String getListener(int index) {\n        return listener_.get(index);\n      }\n      /**\n       * <code>repeated string listener = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getListenerBytes(int index) {\n        return listener_.getByteString(index);\n      }\n      /**\n       * <code>repeated string listener = 3;</code>\n       */\n      public Builder setListener(\n          int index, java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureListenerIsMutable();\n        listener_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string listener = 3;</code>\n       */\n      public Builder addListener(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureListenerIsMutable();\n        listener_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string listener = 3;</code>\n       */\n      public Builder addAllListener(\n          java.lang.Iterable<java.lang.String> values) {\n        ensureListenerIsMutable();\n        super.addAll(values, listener_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string listener = 3;</code>\n       */\n      public Builder clearListener() {\n        listener_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string listener = 3;</code>\n       */\n      public Builder addListenerBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureListenerIsMutable();\n        listener_.add(value);\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:PullChannelListenerResult)\n    }\n\n    static {\n      defaultInstance = new PullChannelListenerResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:PullChannelListenerResult)\n  }\n\n  public interface ListenChannelOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string channel_id = 1;\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    boolean hasChannelId();\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    java.lang.String getChannelId();\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getChannelIdBytes();\n\n    // required int32 listen = 2;\n    /**\n     * <code>required int32 listen = 2;</code>\n     */\n    boolean hasListen();\n    /**\n     * <code>required int32 listen = 2;</code>\n     */\n    int getListen();\n  }\n  /**\n   * Protobuf type {@code ListenChannel}\n   */\n  public static final class ListenChannel extends\n      com.google.protobuf.GeneratedMessage\n      implements ListenChannelOrBuilder {\n    // Use ListenChannel.newBuilder() to construct.\n    private ListenChannel(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ListenChannel(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ListenChannel defaultInstance;\n    public static ListenChannel getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ListenChannel getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ListenChannel(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              channelId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              listen_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ListenChannel_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ListenChannel_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ListenChannel.class, cn.wildfirechat.proto.WFCMessage.ListenChannel.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ListenChannel> PARSER =\n        new com.google.protobuf.AbstractParser<ListenChannel>() {\n      public ListenChannel parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ListenChannel(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ListenChannel> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string channel_id = 1;\n    public static final int CHANNEL_ID_FIELD_NUMBER = 1;\n    private java.lang.Object channelId_;\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public boolean hasChannelId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public java.lang.String getChannelId() {\n      java.lang.Object ref = channelId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          channelId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string channel_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getChannelIdBytes() {\n      java.lang.Object ref = channelId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        channelId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 listen = 2;\n    public static final int LISTEN_FIELD_NUMBER = 2;\n    private int listen_;\n    /**\n     * <code>required int32 listen = 2;</code>\n     */\n    public boolean hasListen() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 listen = 2;</code>\n     */\n    public int getListen() {\n      return listen_;\n    }\n\n    private void initFields() {\n      channelId_ = \"\";\n      listen_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasChannelId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasListen()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getChannelIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, listen_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getChannelIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, listen_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ListenChannel parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ListenChannel parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ListenChannel parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ListenChannel parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ListenChannel parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ListenChannel parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ListenChannel parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ListenChannel parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ListenChannel parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ListenChannel parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ListenChannel prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ListenChannel}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ListenChannelOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ListenChannel_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ListenChannel_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ListenChannel.class, cn.wildfirechat.proto.WFCMessage.ListenChannel.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ListenChannel.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        channelId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        listen_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ListenChannel_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ListenChannel getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ListenChannel.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ListenChannel build() {\n        cn.wildfirechat.proto.WFCMessage.ListenChannel result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ListenChannel buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ListenChannel result = new cn.wildfirechat.proto.WFCMessage.ListenChannel(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.channelId_ = channelId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.listen_ = listen_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ListenChannel) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ListenChannel)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ListenChannel other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ListenChannel.getDefaultInstance()) return this;\n        if (other.hasChannelId()) {\n          bitField0_ |= 0x00000001;\n          channelId_ = other.channelId_;\n          onChanged();\n        }\n        if (other.hasListen()) {\n          setListen(other.getListen());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasChannelId()) {\n          \n          return false;\n        }\n        if (!hasListen()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ListenChannel parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ListenChannel) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string channel_id = 1;\n      private java.lang.Object channelId_ = \"\";\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public boolean hasChannelId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public java.lang.String getChannelId() {\n        java.lang.Object ref = channelId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          channelId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getChannelIdBytes() {\n        java.lang.Object ref = channelId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          channelId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder setChannelId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        channelId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder clearChannelId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        channelId_ = getDefaultInstance().getChannelId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string channel_id = 1;</code>\n       */\n      public Builder setChannelIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        channelId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 listen = 2;\n      private int listen_ ;\n      /**\n       * <code>required int32 listen = 2;</code>\n       */\n      public boolean hasListen() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 listen = 2;</code>\n       */\n      public int getListen() {\n        return listen_;\n      }\n      /**\n       * <code>required int32 listen = 2;</code>\n       */\n      public Builder setListen(int value) {\n        bitField0_ |= 0x00000002;\n        listen_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 listen = 2;</code>\n       */\n      public Builder clearListen() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        listen_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ListenChannel)\n    }\n\n    static {\n      defaultInstance = new ListenChannel(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ListenChannel)\n  }\n\n  public interface SearchChannelResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .ChannelInfo channel = 1;\n    /**\n     * <code>repeated .ChannelInfo channel = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelInfo> \n        getChannelList();\n    /**\n     * <code>repeated .ChannelInfo channel = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.ChannelInfo getChannel(int index);\n    /**\n     * <code>repeated .ChannelInfo channel = 1;</code>\n     */\n    int getChannelCount();\n    /**\n     * <code>repeated .ChannelInfo channel = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.ChannelInfoOrBuilder> \n        getChannelOrBuilderList();\n    /**\n     * <code>repeated .ChannelInfo channel = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.ChannelInfoOrBuilder getChannelOrBuilder(\n        int index);\n\n    // required string keyword = 2;\n    /**\n     * <code>required string keyword = 2;</code>\n     */\n    boolean hasKeyword();\n    /**\n     * <code>required string keyword = 2;</code>\n     */\n    java.lang.String getKeyword();\n    /**\n     * <code>required string keyword = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getKeywordBytes();\n  }\n  /**\n   * Protobuf type {@code SearchChannelResult}\n   */\n  public static final class SearchChannelResult extends\n      com.google.protobuf.GeneratedMessage\n      implements SearchChannelResultOrBuilder {\n    // Use SearchChannelResult.newBuilder() to construct.\n    private SearchChannelResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private SearchChannelResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final SearchChannelResult defaultInstance;\n    public static SearchChannelResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public SearchChannelResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private SearchChannelResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                channel_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.ChannelInfo>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              channel_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.ChannelInfo.PARSER, extensionRegistry));\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000001;\n              keyword_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          channel_ = java.util.Collections.unmodifiableList(channel_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_SearchChannelResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_SearchChannelResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.SearchChannelResult.class, cn.wildfirechat.proto.WFCMessage.SearchChannelResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<SearchChannelResult> PARSER =\n        new com.google.protobuf.AbstractParser<SearchChannelResult>() {\n      public SearchChannelResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new SearchChannelResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<SearchChannelResult> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // repeated .ChannelInfo channel = 1;\n    public static final int CHANNEL_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelInfo> channel_;\n    /**\n     * <code>repeated .ChannelInfo channel = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelInfo> getChannelList() {\n      return channel_;\n    }\n    /**\n     * <code>repeated .ChannelInfo channel = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.ChannelInfoOrBuilder> \n        getChannelOrBuilderList() {\n      return channel_;\n    }\n    /**\n     * <code>repeated .ChannelInfo channel = 1;</code>\n     */\n    public int getChannelCount() {\n      return channel_.size();\n    }\n    /**\n     * <code>repeated .ChannelInfo channel = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.ChannelInfo getChannel(int index) {\n      return channel_.get(index);\n    }\n    /**\n     * <code>repeated .ChannelInfo channel = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.ChannelInfoOrBuilder getChannelOrBuilder(\n        int index) {\n      return channel_.get(index);\n    }\n\n    // required string keyword = 2;\n    public static final int KEYWORD_FIELD_NUMBER = 2;\n    private java.lang.Object keyword_;\n    /**\n     * <code>required string keyword = 2;</code>\n     */\n    public boolean hasKeyword() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string keyword = 2;</code>\n     */\n    public java.lang.String getKeyword() {\n      java.lang.Object ref = keyword_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          keyword_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string keyword = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getKeywordBytes() {\n      java.lang.Object ref = keyword_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        keyword_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      channel_ = java.util.Collections.emptyList();\n      keyword_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasKeyword()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      for (int i = 0; i < getChannelCount(); i++) {\n        if (!getChannel(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < channel_.size(); i++) {\n        output.writeMessage(1, channel_.get(i));\n      }\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(2, getKeywordBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < channel_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, channel_.get(i));\n      }\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getKeywordBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.SearchChannelResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchChannelResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchChannelResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchChannelResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchChannelResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchChannelResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchChannelResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchChannelResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchChannelResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchChannelResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.SearchChannelResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code SearchChannelResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.SearchChannelResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_SearchChannelResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_SearchChannelResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.SearchChannelResult.class, cn.wildfirechat.proto.WFCMessage.SearchChannelResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.SearchChannelResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getChannelFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (channelBuilder_ == null) {\n          channel_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          channelBuilder_.clear();\n        }\n        keyword_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_SearchChannelResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.SearchChannelResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.SearchChannelResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.SearchChannelResult build() {\n        cn.wildfirechat.proto.WFCMessage.SearchChannelResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.SearchChannelResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.SearchChannelResult result = new cn.wildfirechat.proto.WFCMessage.SearchChannelResult(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (channelBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            channel_ = java.util.Collections.unmodifiableList(channel_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.channel_ = channel_;\n        } else {\n          result.channel_ = channelBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.keyword_ = keyword_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.SearchChannelResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.SearchChannelResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.SearchChannelResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.SearchChannelResult.getDefaultInstance()) return this;\n        if (channelBuilder_ == null) {\n          if (!other.channel_.isEmpty()) {\n            if (channel_.isEmpty()) {\n              channel_ = other.channel_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureChannelIsMutable();\n              channel_.addAll(other.channel_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.channel_.isEmpty()) {\n            if (channelBuilder_.isEmpty()) {\n              channelBuilder_.dispose();\n              channelBuilder_ = null;\n              channel_ = other.channel_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              channelBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getChannelFieldBuilder() : null;\n            } else {\n              channelBuilder_.addAllMessages(other.channel_);\n            }\n          }\n        }\n        if (other.hasKeyword()) {\n          bitField0_ |= 0x00000002;\n          keyword_ = other.keyword_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasKeyword()) {\n          \n          return false;\n        }\n        for (int i = 0; i < getChannelCount(); i++) {\n          if (!getChannel(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.SearchChannelResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.SearchChannelResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .ChannelInfo channel = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelInfo> channel_ =\n        java.util.Collections.emptyList();\n      private void ensureChannelIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          channel_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.ChannelInfo>(channel_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.ChannelInfo, cn.wildfirechat.proto.WFCMessage.ChannelInfo.Builder, cn.wildfirechat.proto.WFCMessage.ChannelInfoOrBuilder> channelBuilder_;\n\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelInfo> getChannelList() {\n        if (channelBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(channel_);\n        } else {\n          return channelBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public int getChannelCount() {\n        if (channelBuilder_ == null) {\n          return channel_.size();\n        } else {\n          return channelBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelInfo getChannel(int index) {\n        if (channelBuilder_ == null) {\n          return channel_.get(index);\n        } else {\n          return channelBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public Builder setChannel(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelInfo value) {\n        if (channelBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureChannelIsMutable();\n          channel_.set(index, value);\n          onChanged();\n        } else {\n          channelBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public Builder setChannel(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelInfo.Builder builderForValue) {\n        if (channelBuilder_ == null) {\n          ensureChannelIsMutable();\n          channel_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          channelBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public Builder addChannel(cn.wildfirechat.proto.WFCMessage.ChannelInfo value) {\n        if (channelBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureChannelIsMutable();\n          channel_.add(value);\n          onChanged();\n        } else {\n          channelBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public Builder addChannel(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelInfo value) {\n        if (channelBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureChannelIsMutable();\n          channel_.add(index, value);\n          onChanged();\n        } else {\n          channelBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public Builder addChannel(\n          cn.wildfirechat.proto.WFCMessage.ChannelInfo.Builder builderForValue) {\n        if (channelBuilder_ == null) {\n          ensureChannelIsMutable();\n          channel_.add(builderForValue.build());\n          onChanged();\n        } else {\n          channelBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public Builder addChannel(\n          int index, cn.wildfirechat.proto.WFCMessage.ChannelInfo.Builder builderForValue) {\n        if (channelBuilder_ == null) {\n          ensureChannelIsMutable();\n          channel_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          channelBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public Builder addAllChannel(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.ChannelInfo> values) {\n        if (channelBuilder_ == null) {\n          ensureChannelIsMutable();\n          super.addAll(values, channel_);\n          onChanged();\n        } else {\n          channelBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public Builder clearChannel() {\n        if (channelBuilder_ == null) {\n          channel_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          channelBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public Builder removeChannel(int index) {\n        if (channelBuilder_ == null) {\n          ensureChannelIsMutable();\n          channel_.remove(index);\n          onChanged();\n        } else {\n          channelBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelInfo.Builder getChannelBuilder(\n          int index) {\n        return getChannelFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelInfoOrBuilder getChannelOrBuilder(\n          int index) {\n        if (channelBuilder_ == null) {\n          return channel_.get(index);  } else {\n          return channelBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.ChannelInfoOrBuilder> \n           getChannelOrBuilderList() {\n        if (channelBuilder_ != null) {\n          return channelBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(channel_);\n        }\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelInfo.Builder addChannelBuilder() {\n        return getChannelFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.ChannelInfo.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ChannelInfo.Builder addChannelBuilder(\n          int index) {\n        return getChannelFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.ChannelInfo.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .ChannelInfo channel = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.ChannelInfo.Builder> \n           getChannelBuilderList() {\n        return getChannelFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.ChannelInfo, cn.wildfirechat.proto.WFCMessage.ChannelInfo.Builder, cn.wildfirechat.proto.WFCMessage.ChannelInfoOrBuilder> \n          getChannelFieldBuilder() {\n        if (channelBuilder_ == null) {\n          channelBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.ChannelInfo, cn.wildfirechat.proto.WFCMessage.ChannelInfo.Builder, cn.wildfirechat.proto.WFCMessage.ChannelInfoOrBuilder>(\n                  channel_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          channel_ = null;\n        }\n        return channelBuilder_;\n      }\n\n      // required string keyword = 2;\n      private java.lang.Object keyword_ = \"\";\n      /**\n       * <code>required string keyword = 2;</code>\n       */\n      public boolean hasKeyword() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string keyword = 2;</code>\n       */\n      public java.lang.String getKeyword() {\n        java.lang.Object ref = keyword_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          keyword_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string keyword = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getKeywordBytes() {\n        java.lang.Object ref = keyword_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          keyword_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string keyword = 2;</code>\n       */\n      public Builder setKeyword(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        keyword_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string keyword = 2;</code>\n       */\n      public Builder clearKeyword() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        keyword_ = getDefaultInstance().getKeyword();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string keyword = 2;</code>\n       */\n      public Builder setKeywordBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        keyword_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:SearchChannelResult)\n    }\n\n    static {\n      defaultInstance = new SearchChannelResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:SearchChannelResult)\n  }\n\n  public interface MessageContentOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int32 type = 1;\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    int getType();\n\n    // optional string searchable_content = 2;\n    /**\n     * <code>optional string searchable_content = 2;</code>\n     */\n    boolean hasSearchableContent();\n    /**\n     * <code>optional string searchable_content = 2;</code>\n     */\n    java.lang.String getSearchableContent();\n    /**\n     * <code>optional string searchable_content = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getSearchableContentBytes();\n\n    // optional string push_content = 3;\n    /**\n     * <code>optional string push_content = 3;</code>\n     */\n    boolean hasPushContent();\n    /**\n     * <code>optional string push_content = 3;</code>\n     */\n    java.lang.String getPushContent();\n    /**\n     * <code>optional string push_content = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getPushContentBytes();\n\n    // optional string content = 4;\n    /**\n     * <code>optional string content = 4;</code>\n     */\n    boolean hasContent();\n    /**\n     * <code>optional string content = 4;</code>\n     */\n    java.lang.String getContent();\n    /**\n     * <code>optional string content = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getContentBytes();\n\n    // optional bytes data = 5;\n    /**\n     * <code>optional bytes data = 5;</code>\n     */\n    boolean hasData();\n    /**\n     * <code>optional bytes data = 5;</code>\n     */\n    com.google.protobuf.ByteString getData();\n\n    // optional int32 mediaType = 6;\n    /**\n     * <code>optional int32 mediaType = 6;</code>\n     */\n    boolean hasMediaType();\n    /**\n     * <code>optional int32 mediaType = 6;</code>\n     */\n    int getMediaType();\n\n    // optional string remoteMediaUrl = 7;\n    /**\n     * <code>optional string remoteMediaUrl = 7;</code>\n     */\n    boolean hasRemoteMediaUrl();\n    /**\n     * <code>optional string remoteMediaUrl = 7;</code>\n     */\n    java.lang.String getRemoteMediaUrl();\n    /**\n     * <code>optional string remoteMediaUrl = 7;</code>\n     */\n    com.google.protobuf.ByteString\n        getRemoteMediaUrlBytes();\n\n    // optional int32 persist_flag = 8;\n    /**\n     * <code>optional int32 persist_flag = 8;</code>\n     */\n    boolean hasPersistFlag();\n    /**\n     * <code>optional int32 persist_flag = 8;</code>\n     */\n    int getPersistFlag();\n\n    // optional int32 expire_duration = 9;\n    /**\n     * <code>optional int32 expire_duration = 9;</code>\n     */\n    boolean hasExpireDuration();\n    /**\n     * <code>optional int32 expire_duration = 9;</code>\n     */\n    int getExpireDuration();\n\n    // optional int32 mentioned_type = 10;\n    /**\n     * <code>optional int32 mentioned_type = 10;</code>\n     */\n    boolean hasMentionedType();\n    /**\n     * <code>optional int32 mentioned_type = 10;</code>\n     */\n    int getMentionedType();\n\n    // repeated string mentioned_target = 11;\n    /**\n     * <code>repeated string mentioned_target = 11;</code>\n     */\n    java.util.List<java.lang.String>\n    getMentionedTargetList();\n    /**\n     * <code>repeated string mentioned_target = 11;</code>\n     */\n    int getMentionedTargetCount();\n    /**\n     * <code>repeated string mentioned_target = 11;</code>\n     */\n    java.lang.String getMentionedTarget(int index);\n    /**\n     * <code>repeated string mentioned_target = 11;</code>\n     */\n    com.google.protobuf.ByteString\n        getMentionedTargetBytes(int index);\n\n    // optional string extra = 12;\n    /**\n     * <code>optional string extra = 12;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 12;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 12;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n\n    // optional string push_data = 13;\n    /**\n     * <code>optional string push_data = 13;</code>\n     */\n    boolean hasPushData();\n    /**\n     * <code>optional string push_data = 13;</code>\n     */\n    java.lang.String getPushData();\n    /**\n     * <code>optional string push_data = 13;</code>\n     */\n    com.google.protobuf.ByteString\n        getPushDataBytes();\n  }\n  /**\n   * Protobuf type {@code MessageContent}\n   */\n  public static final class MessageContent extends\n      com.google.protobuf.GeneratedMessage\n      implements MessageContentOrBuilder {\n    // Use MessageContent.newBuilder() to construct.\n    private MessageContent(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private MessageContent(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final MessageContent defaultInstance;\n    public static MessageContent getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public MessageContent getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private MessageContent(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              type_ = input.readInt32();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              searchableContent_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              pushContent_ = input.readBytes();\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000008;\n              content_ = input.readBytes();\n              break;\n            }\n            case 42: {\n              bitField0_ |= 0x00000010;\n              data_ = input.readBytes();\n              break;\n            }\n            case 48: {\n              bitField0_ |= 0x00000020;\n              mediaType_ = input.readInt32();\n              break;\n            }\n            case 58: {\n              bitField0_ |= 0x00000040;\n              remoteMediaUrl_ = input.readBytes();\n              break;\n            }\n            case 64: {\n              bitField0_ |= 0x00000080;\n              persistFlag_ = input.readInt32();\n              break;\n            }\n            case 72: {\n              bitField0_ |= 0x00000100;\n              expireDuration_ = input.readInt32();\n              break;\n            }\n            case 80: {\n              bitField0_ |= 0x00000200;\n              mentionedType_ = input.readInt32();\n              break;\n            }\n            case 90: {\n              if (!((mutable_bitField0_ & 0x00000400) == 0x00000400)) {\n                mentionedTarget_ = new com.google.protobuf.LazyStringArrayList();\n                mutable_bitField0_ |= 0x00000400;\n              }\n              mentionedTarget_.add(input.readBytes());\n              break;\n            }\n            case 98: {\n              bitField0_ |= 0x00000400;\n              extra_ = input.readBytes();\n              break;\n            }\n            case 106: {\n              bitField0_ |= 0x00000800;\n              pushData_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000400) == 0x00000400)) {\n          mentionedTarget_ = new com.google.protobuf.UnmodifiableLazyStringList(mentionedTarget_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_MessageContent_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_MessageContent_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.MessageContent.class, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<MessageContent> PARSER =\n        new com.google.protobuf.AbstractParser<MessageContent>() {\n      public MessageContent parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new MessageContent(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<MessageContent> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int32 type = 1;\n    public static final int TYPE_FIELD_NUMBER = 1;\n    private int type_;\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    // optional string searchable_content = 2;\n    public static final int SEARCHABLE_CONTENT_FIELD_NUMBER = 2;\n    private java.lang.Object searchableContent_;\n    /**\n     * <code>optional string searchable_content = 2;</code>\n     */\n    public boolean hasSearchableContent() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional string searchable_content = 2;</code>\n     */\n    public java.lang.String getSearchableContent() {\n      java.lang.Object ref = searchableContent_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          searchableContent_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string searchable_content = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getSearchableContentBytes() {\n      java.lang.Object ref = searchableContent_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        searchableContent_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string push_content = 3;\n    public static final int PUSH_CONTENT_FIELD_NUMBER = 3;\n    private java.lang.Object pushContent_;\n    /**\n     * <code>optional string push_content = 3;</code>\n     */\n    public boolean hasPushContent() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string push_content = 3;</code>\n     */\n    public java.lang.String getPushContent() {\n      java.lang.Object ref = pushContent_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          pushContent_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string push_content = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getPushContentBytes() {\n      java.lang.Object ref = pushContent_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        pushContent_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string content = 4;\n    public static final int CONTENT_FIELD_NUMBER = 4;\n    private java.lang.Object content_;\n    /**\n     * <code>optional string content = 4;</code>\n     */\n    public boolean hasContent() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional string content = 4;</code>\n     */\n    public java.lang.String getContent() {\n      java.lang.Object ref = content_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          content_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string content = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getContentBytes() {\n      java.lang.Object ref = content_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        content_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional bytes data = 5;\n    public static final int DATA_FIELD_NUMBER = 5;\n    private com.google.protobuf.ByteString data_;\n    /**\n     * <code>optional bytes data = 5;</code>\n     */\n    public boolean hasData() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional bytes data = 5;</code>\n     */\n    public com.google.protobuf.ByteString getData() {\n      return data_;\n    }\n\n    // optional int32 mediaType = 6;\n    public static final int MEDIATYPE_FIELD_NUMBER = 6;\n    private int mediaType_;\n    /**\n     * <code>optional int32 mediaType = 6;</code>\n     */\n    public boolean hasMediaType() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional int32 mediaType = 6;</code>\n     */\n    public int getMediaType() {\n      return mediaType_;\n    }\n\n    // optional string remoteMediaUrl = 7;\n    public static final int REMOTEMEDIAURL_FIELD_NUMBER = 7;\n    private java.lang.Object remoteMediaUrl_;\n    /**\n     * <code>optional string remoteMediaUrl = 7;</code>\n     */\n    public boolean hasRemoteMediaUrl() {\n      return ((bitField0_ & 0x00000040) == 0x00000040);\n    }\n    /**\n     * <code>optional string remoteMediaUrl = 7;</code>\n     */\n    public java.lang.String getRemoteMediaUrl() {\n      java.lang.Object ref = remoteMediaUrl_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          remoteMediaUrl_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string remoteMediaUrl = 7;</code>\n     */\n    public com.google.protobuf.ByteString\n        getRemoteMediaUrlBytes() {\n      java.lang.Object ref = remoteMediaUrl_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        remoteMediaUrl_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 persist_flag = 8;\n    public static final int PERSIST_FLAG_FIELD_NUMBER = 8;\n    private int persistFlag_;\n    /**\n     * <code>optional int32 persist_flag = 8;</code>\n     */\n    public boolean hasPersistFlag() {\n      return ((bitField0_ & 0x00000080) == 0x00000080);\n    }\n    /**\n     * <code>optional int32 persist_flag = 8;</code>\n     */\n    public int getPersistFlag() {\n      return persistFlag_;\n    }\n\n    // optional int32 expire_duration = 9;\n    public static final int EXPIRE_DURATION_FIELD_NUMBER = 9;\n    private int expireDuration_;\n    /**\n     * <code>optional int32 expire_duration = 9;</code>\n     */\n    public boolean hasExpireDuration() {\n      return ((bitField0_ & 0x00000100) == 0x00000100);\n    }\n    /**\n     * <code>optional int32 expire_duration = 9;</code>\n     */\n    public int getExpireDuration() {\n      return expireDuration_;\n    }\n\n    // optional int32 mentioned_type = 10;\n    public static final int MENTIONED_TYPE_FIELD_NUMBER = 10;\n    private int mentionedType_;\n    /**\n     * <code>optional int32 mentioned_type = 10;</code>\n     */\n    public boolean hasMentionedType() {\n      return ((bitField0_ & 0x00000200) == 0x00000200);\n    }\n    /**\n     * <code>optional int32 mentioned_type = 10;</code>\n     */\n    public int getMentionedType() {\n      return mentionedType_;\n    }\n\n    // repeated string mentioned_target = 11;\n    public static final int MENTIONED_TARGET_FIELD_NUMBER = 11;\n    private com.google.protobuf.LazyStringList mentionedTarget_;\n    /**\n     * <code>repeated string mentioned_target = 11;</code>\n     */\n    public java.util.List<java.lang.String>\n        getMentionedTargetList() {\n      return mentionedTarget_;\n    }\n    /**\n     * <code>repeated string mentioned_target = 11;</code>\n     */\n    public int getMentionedTargetCount() {\n      return mentionedTarget_.size();\n    }\n    /**\n     * <code>repeated string mentioned_target = 11;</code>\n     */\n    public java.lang.String getMentionedTarget(int index) {\n      return mentionedTarget_.get(index);\n    }\n    /**\n     * <code>repeated string mentioned_target = 11;</code>\n     */\n    public com.google.protobuf.ByteString\n        getMentionedTargetBytes(int index) {\n      return mentionedTarget_.getByteString(index);\n    }\n\n    // optional string extra = 12;\n    public static final int EXTRA_FIELD_NUMBER = 12;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 12;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000400) == 0x00000400);\n    }\n    /**\n     * <code>optional string extra = 12;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 12;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string push_data = 13;\n    public static final int PUSH_DATA_FIELD_NUMBER = 13;\n    private java.lang.Object pushData_;\n    /**\n     * <code>optional string push_data = 13;</code>\n     */\n    public boolean hasPushData() {\n      return ((bitField0_ & 0x00000800) == 0x00000800);\n    }\n    /**\n     * <code>optional string push_data = 13;</code>\n     */\n    public java.lang.String getPushData() {\n      java.lang.Object ref = pushData_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          pushData_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string push_data = 13;</code>\n     */\n    public com.google.protobuf.ByteString\n        getPushDataBytes() {\n      java.lang.Object ref = pushData_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        pushData_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      type_ = 0;\n      searchableContent_ = \"\";\n      pushContent_ = \"\";\n      content_ = \"\";\n      data_ = com.google.protobuf.ByteString.EMPTY;\n      mediaType_ = 0;\n      remoteMediaUrl_ = \"\";\n      persistFlag_ = 0;\n      expireDuration_ = 0;\n      mentionedType_ = 0;\n      mentionedTarget_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      extra_ = \"\";\n      pushData_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, type_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getSearchableContentBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getPushContentBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(4, getContentBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeBytes(5, data_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeInt32(6, mediaType_);\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        output.writeBytes(7, getRemoteMediaUrlBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        output.writeInt32(8, persistFlag_);\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        output.writeInt32(9, expireDuration_);\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        output.writeInt32(10, mentionedType_);\n      }\n      for (int i = 0; i < mentionedTarget_.size(); i++) {\n        output.writeBytes(11, mentionedTarget_.getByteString(i));\n      }\n      if (((bitField0_ & 0x00000400) == 0x00000400)) {\n        output.writeBytes(12, getExtraBytes());\n      }\n      if (((bitField0_ & 0x00000800) == 0x00000800)) {\n        output.writeBytes(13, getPushDataBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, type_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getSearchableContentBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getPushContentBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, getContentBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5, data_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(6, mediaType_);\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(7, getRemoteMediaUrlBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(8, persistFlag_);\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(9, expireDuration_);\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(10, mentionedType_);\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < mentionedTarget_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeBytesSizeNoTag(mentionedTarget_.getByteString(i));\n        }\n        size += dataSize;\n        size += 1 * getMentionedTargetList().size();\n      }\n      if (((bitField0_ & 0x00000400) == 0x00000400)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(12, getExtraBytes());\n      }\n      if (((bitField0_ & 0x00000800) == 0x00000800)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(13, getPushDataBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.MessageContent parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MessageContent parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MessageContent parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MessageContent parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MessageContent parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MessageContent parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MessageContent parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MessageContent parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MessageContent parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MessageContent parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.MessageContent prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code MessageContent}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_MessageContent_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_MessageContent_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.MessageContent.class, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        searchableContent_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        pushContent_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        content_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        data_ = com.google.protobuf.ByteString.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000010);\n        mediaType_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000020);\n        remoteMediaUrl_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000040);\n        persistFlag_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000080);\n        expireDuration_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000100);\n        mentionedType_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000200);\n        mentionedTarget_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000400);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000800);\n        pushData_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00001000);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_MessageContent_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.MessageContent build() {\n        cn.wildfirechat.proto.WFCMessage.MessageContent result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.MessageContent buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.MessageContent result = new cn.wildfirechat.proto.WFCMessage.MessageContent(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.type_ = type_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.searchableContent_ = searchableContent_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.pushContent_ = pushContent_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.content_ = content_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.data_ = data_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.mediaType_ = mediaType_;\n        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {\n          to_bitField0_ |= 0x00000040;\n        }\n        result.remoteMediaUrl_ = remoteMediaUrl_;\n        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {\n          to_bitField0_ |= 0x00000080;\n        }\n        result.persistFlag_ = persistFlag_;\n        if (((from_bitField0_ & 0x00000100) == 0x00000100)) {\n          to_bitField0_ |= 0x00000100;\n        }\n        result.expireDuration_ = expireDuration_;\n        if (((from_bitField0_ & 0x00000200) == 0x00000200)) {\n          to_bitField0_ |= 0x00000200;\n        }\n        result.mentionedType_ = mentionedType_;\n        if (((bitField0_ & 0x00000400) == 0x00000400)) {\n          mentionedTarget_ = new com.google.protobuf.UnmodifiableLazyStringList(\n              mentionedTarget_);\n          bitField0_ = (bitField0_ & ~0x00000400);\n        }\n        result.mentionedTarget_ = mentionedTarget_;\n        if (((from_bitField0_ & 0x00000800) == 0x00000800)) {\n          to_bitField0_ |= 0x00000400;\n        }\n        result.extra_ = extra_;\n        if (((from_bitField0_ & 0x00001000) == 0x00001000)) {\n          to_bitField0_ |= 0x00000800;\n        }\n        result.pushData_ = pushData_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.MessageContent) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.MessageContent)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.MessageContent other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) return this;\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        if (other.hasSearchableContent()) {\n          bitField0_ |= 0x00000002;\n          searchableContent_ = other.searchableContent_;\n          onChanged();\n        }\n        if (other.hasPushContent()) {\n          bitField0_ |= 0x00000004;\n          pushContent_ = other.pushContent_;\n          onChanged();\n        }\n        if (other.hasContent()) {\n          bitField0_ |= 0x00000008;\n          content_ = other.content_;\n          onChanged();\n        }\n        if (other.hasData()) {\n          setData(other.getData());\n        }\n        if (other.hasMediaType()) {\n          setMediaType(other.getMediaType());\n        }\n        if (other.hasRemoteMediaUrl()) {\n          bitField0_ |= 0x00000040;\n          remoteMediaUrl_ = other.remoteMediaUrl_;\n          onChanged();\n        }\n        if (other.hasPersistFlag()) {\n          setPersistFlag(other.getPersistFlag());\n        }\n        if (other.hasExpireDuration()) {\n          setExpireDuration(other.getExpireDuration());\n        }\n        if (other.hasMentionedType()) {\n          setMentionedType(other.getMentionedType());\n        }\n        if (!other.mentionedTarget_.isEmpty()) {\n          if (mentionedTarget_.isEmpty()) {\n            mentionedTarget_ = other.mentionedTarget_;\n            bitField0_ = (bitField0_ & ~0x00000400);\n          } else {\n            ensureMentionedTargetIsMutable();\n            mentionedTarget_.addAll(other.mentionedTarget_);\n          }\n          onChanged();\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000800;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        if (other.hasPushData()) {\n          bitField0_ |= 0x00001000;\n          pushData_ = other.pushData_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasType()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.MessageContent parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.MessageContent) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int32 type = 1;\n      private int type_ ;\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00000001;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional string searchable_content = 2;\n      private java.lang.Object searchableContent_ = \"\";\n      /**\n       * <code>optional string searchable_content = 2;</code>\n       */\n      public boolean hasSearchableContent() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional string searchable_content = 2;</code>\n       */\n      public java.lang.String getSearchableContent() {\n        java.lang.Object ref = searchableContent_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          searchableContent_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string searchable_content = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getSearchableContentBytes() {\n        java.lang.Object ref = searchableContent_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          searchableContent_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string searchable_content = 2;</code>\n       */\n      public Builder setSearchableContent(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        searchableContent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string searchable_content = 2;</code>\n       */\n      public Builder clearSearchableContent() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        searchableContent_ = getDefaultInstance().getSearchableContent();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string searchable_content = 2;</code>\n       */\n      public Builder setSearchableContentBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        searchableContent_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string push_content = 3;\n      private java.lang.Object pushContent_ = \"\";\n      /**\n       * <code>optional string push_content = 3;</code>\n       */\n      public boolean hasPushContent() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional string push_content = 3;</code>\n       */\n      public java.lang.String getPushContent() {\n        java.lang.Object ref = pushContent_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          pushContent_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string push_content = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getPushContentBytes() {\n        java.lang.Object ref = pushContent_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          pushContent_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string push_content = 3;</code>\n       */\n      public Builder setPushContent(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        pushContent_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string push_content = 3;</code>\n       */\n      public Builder clearPushContent() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        pushContent_ = getDefaultInstance().getPushContent();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string push_content = 3;</code>\n       */\n      public Builder setPushContentBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        pushContent_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string content = 4;\n      private java.lang.Object content_ = \"\";\n      /**\n       * <code>optional string content = 4;</code>\n       */\n      public boolean hasContent() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional string content = 4;</code>\n       */\n      public java.lang.String getContent() {\n        java.lang.Object ref = content_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          content_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string content = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getContentBytes() {\n        java.lang.Object ref = content_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          content_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string content = 4;</code>\n       */\n      public Builder setContent(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        content_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string content = 4;</code>\n       */\n      public Builder clearContent() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        content_ = getDefaultInstance().getContent();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string content = 4;</code>\n       */\n      public Builder setContentBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        content_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional bytes data = 5;\n      private com.google.protobuf.ByteString data_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <code>optional bytes data = 5;</code>\n       */\n      public boolean hasData() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional bytes data = 5;</code>\n       */\n      public com.google.protobuf.ByteString getData() {\n        return data_;\n      }\n      /**\n       * <code>optional bytes data = 5;</code>\n       */\n      public Builder setData(com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        data_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional bytes data = 5;</code>\n       */\n      public Builder clearData() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        data_ = getDefaultInstance().getData();\n        onChanged();\n        return this;\n      }\n\n      // optional int32 mediaType = 6;\n      private int mediaType_ ;\n      /**\n       * <code>optional int32 mediaType = 6;</code>\n       */\n      public boolean hasMediaType() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional int32 mediaType = 6;</code>\n       */\n      public int getMediaType() {\n        return mediaType_;\n      }\n      /**\n       * <code>optional int32 mediaType = 6;</code>\n       */\n      public Builder setMediaType(int value) {\n        bitField0_ |= 0x00000020;\n        mediaType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 mediaType = 6;</code>\n       */\n      public Builder clearMediaType() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        mediaType_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional string remoteMediaUrl = 7;\n      private java.lang.Object remoteMediaUrl_ = \"\";\n      /**\n       * <code>optional string remoteMediaUrl = 7;</code>\n       */\n      public boolean hasRemoteMediaUrl() {\n        return ((bitField0_ & 0x00000040) == 0x00000040);\n      }\n      /**\n       * <code>optional string remoteMediaUrl = 7;</code>\n       */\n      public java.lang.String getRemoteMediaUrl() {\n        java.lang.Object ref = remoteMediaUrl_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          remoteMediaUrl_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string remoteMediaUrl = 7;</code>\n       */\n      public com.google.protobuf.ByteString\n          getRemoteMediaUrlBytes() {\n        java.lang.Object ref = remoteMediaUrl_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          remoteMediaUrl_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string remoteMediaUrl = 7;</code>\n       */\n      public Builder setRemoteMediaUrl(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        remoteMediaUrl_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string remoteMediaUrl = 7;</code>\n       */\n      public Builder clearRemoteMediaUrl() {\n        bitField0_ = (bitField0_ & ~0x00000040);\n        remoteMediaUrl_ = getDefaultInstance().getRemoteMediaUrl();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string remoteMediaUrl = 7;</code>\n       */\n      public Builder setRemoteMediaUrlBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        remoteMediaUrl_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 persist_flag = 8;\n      private int persistFlag_ ;\n      /**\n       * <code>optional int32 persist_flag = 8;</code>\n       */\n      public boolean hasPersistFlag() {\n        return ((bitField0_ & 0x00000080) == 0x00000080);\n      }\n      /**\n       * <code>optional int32 persist_flag = 8;</code>\n       */\n      public int getPersistFlag() {\n        return persistFlag_;\n      }\n      /**\n       * <code>optional int32 persist_flag = 8;</code>\n       */\n      public Builder setPersistFlag(int value) {\n        bitField0_ |= 0x00000080;\n        persistFlag_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 persist_flag = 8;</code>\n       */\n      public Builder clearPersistFlag() {\n        bitField0_ = (bitField0_ & ~0x00000080);\n        persistFlag_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 expire_duration = 9;\n      private int expireDuration_ ;\n      /**\n       * <code>optional int32 expire_duration = 9;</code>\n       */\n      public boolean hasExpireDuration() {\n        return ((bitField0_ & 0x00000100) == 0x00000100);\n      }\n      /**\n       * <code>optional int32 expire_duration = 9;</code>\n       */\n      public int getExpireDuration() {\n        return expireDuration_;\n      }\n      /**\n       * <code>optional int32 expire_duration = 9;</code>\n       */\n      public Builder setExpireDuration(int value) {\n        bitField0_ |= 0x00000100;\n        expireDuration_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 expire_duration = 9;</code>\n       */\n      public Builder clearExpireDuration() {\n        bitField0_ = (bitField0_ & ~0x00000100);\n        expireDuration_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 mentioned_type = 10;\n      private int mentionedType_ ;\n      /**\n       * <code>optional int32 mentioned_type = 10;</code>\n       */\n      public boolean hasMentionedType() {\n        return ((bitField0_ & 0x00000200) == 0x00000200);\n      }\n      /**\n       * <code>optional int32 mentioned_type = 10;</code>\n       */\n      public int getMentionedType() {\n        return mentionedType_;\n      }\n      /**\n       * <code>optional int32 mentioned_type = 10;</code>\n       */\n      public Builder setMentionedType(int value) {\n        bitField0_ |= 0x00000200;\n        mentionedType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 mentioned_type = 10;</code>\n       */\n      public Builder clearMentionedType() {\n        bitField0_ = (bitField0_ & ~0x00000200);\n        mentionedType_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // repeated string mentioned_target = 11;\n      private com.google.protobuf.LazyStringList mentionedTarget_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      private void ensureMentionedTargetIsMutable() {\n        if (!((bitField0_ & 0x00000400) == 0x00000400)) {\n          mentionedTarget_ = new com.google.protobuf.LazyStringArrayList(mentionedTarget_);\n          bitField0_ |= 0x00000400;\n         }\n      }\n      /**\n       * <code>repeated string mentioned_target = 11;</code>\n       */\n      public java.util.List<java.lang.String>\n          getMentionedTargetList() {\n        return java.util.Collections.unmodifiableList(mentionedTarget_);\n      }\n      /**\n       * <code>repeated string mentioned_target = 11;</code>\n       */\n      public int getMentionedTargetCount() {\n        return mentionedTarget_.size();\n      }\n      /**\n       * <code>repeated string mentioned_target = 11;</code>\n       */\n      public java.lang.String getMentionedTarget(int index) {\n        return mentionedTarget_.get(index);\n      }\n      /**\n       * <code>repeated string mentioned_target = 11;</code>\n       */\n      public com.google.protobuf.ByteString\n          getMentionedTargetBytes(int index) {\n        return mentionedTarget_.getByteString(index);\n      }\n      /**\n       * <code>repeated string mentioned_target = 11;</code>\n       */\n      public Builder setMentionedTarget(\n          int index, java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureMentionedTargetIsMutable();\n        mentionedTarget_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string mentioned_target = 11;</code>\n       */\n      public Builder addMentionedTarget(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureMentionedTargetIsMutable();\n        mentionedTarget_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string mentioned_target = 11;</code>\n       */\n      public Builder addAllMentionedTarget(\n          java.lang.Iterable<java.lang.String> values) {\n        ensureMentionedTargetIsMutable();\n        super.addAll(values, mentionedTarget_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string mentioned_target = 11;</code>\n       */\n      public Builder clearMentionedTarget() {\n        mentionedTarget_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000400);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string mentioned_target = 11;</code>\n       */\n      public Builder addMentionedTargetBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureMentionedTargetIsMutable();\n        mentionedTarget_.add(value);\n        onChanged();\n        return this;\n      }\n\n      // optional string extra = 12;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 12;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000800) == 0x00000800);\n      }\n      /**\n       * <code>optional string extra = 12;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 12;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 12;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000800;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 12;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000800);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 12;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000800;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string push_data = 13;\n      private java.lang.Object pushData_ = \"\";\n      /**\n       * <code>optional string push_data = 13;</code>\n       */\n      public boolean hasPushData() {\n        return ((bitField0_ & 0x00001000) == 0x00001000);\n      }\n      /**\n       * <code>optional string push_data = 13;</code>\n       */\n      public java.lang.String getPushData() {\n        java.lang.Object ref = pushData_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          pushData_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string push_data = 13;</code>\n       */\n      public com.google.protobuf.ByteString\n          getPushDataBytes() {\n        java.lang.Object ref = pushData_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          pushData_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string push_data = 13;</code>\n       */\n      public Builder setPushData(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00001000;\n        pushData_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string push_data = 13;</code>\n       */\n      public Builder clearPushData() {\n        bitField0_ = (bitField0_ & ~0x00001000);\n        pushData_ = getDefaultInstance().getPushData();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string push_data = 13;</code>\n       */\n      public Builder setPushDataBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00001000;\n        pushData_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:MessageContent)\n    }\n\n    static {\n      defaultInstance = new MessageContent(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:MessageContent)\n  }\n\n  public interface AddGroupMemberRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string group_id = 1;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    boolean hasGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    java.lang.String getGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getGroupIdBytes();\n\n    // repeated .GroupMember added_member = 2;\n    /**\n     * <code>repeated .GroupMember added_member = 2;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> \n        getAddedMemberList();\n    /**\n     * <code>repeated .GroupMember added_member = 2;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.GroupMember getAddedMember(int index);\n    /**\n     * <code>repeated .GroupMember added_member = 2;</code>\n     */\n    int getAddedMemberCount();\n    /**\n     * <code>repeated .GroupMember added_member = 2;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> \n        getAddedMemberOrBuilderList();\n    /**\n     * <code>repeated .GroupMember added_member = 2;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder getAddedMemberOrBuilder(\n        int index);\n\n    // repeated int32 to_line = 3;\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    java.util.List<java.lang.Integer> getToLineList();\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    int getToLineCount();\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    int getToLine(int index);\n\n    // optional .MessageContent notify_content = 4;\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    boolean hasNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder();\n\n    // optional string extra = 5;\n    /**\n     * <code>optional string extra = 5;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 5;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 5;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n  }\n  /**\n   * Protobuf type {@code AddGroupMemberRequest}\n   */\n  public static final class AddGroupMemberRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements AddGroupMemberRequestOrBuilder {\n    // Use AddGroupMemberRequest.newBuilder() to construct.\n    private AddGroupMemberRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private AddGroupMemberRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final AddGroupMemberRequest defaultInstance;\n    public static AddGroupMemberRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public AddGroupMemberRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private AddGroupMemberRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              groupId_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n                addedMember_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.GroupMember>();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              addedMember_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.GroupMember.PARSER, extensionRegistry));\n              break;\n            }\n            case 24: {\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              toLine_.add(input.readInt32());\n              break;\n            }\n            case 26: {\n              int length = input.readRawVarint32();\n              int limit = input.pushLimit(length);\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004) && input.getBytesUntilLimit() > 0) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              while (input.getBytesUntilLimit() > 0) {\n                toLine_.add(input.readInt32());\n              }\n              input.popLimit(limit);\n              break;\n            }\n            case 34: {\n              cn.wildfirechat.proto.WFCMessage.MessageContent.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                subBuilder = notifyContent_.toBuilder();\n              }\n              notifyContent_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.MessageContent.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(notifyContent_);\n                notifyContent_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000002;\n              break;\n            }\n            case 42: {\n              bitField0_ |= 0x00000004;\n              extra_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n          addedMember_ = java.util.Collections.unmodifiableList(addedMember_);\n        }\n        if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_AddGroupMemberRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_AddGroupMemberRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest.class, cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<AddGroupMemberRequest> PARSER =\n        new com.google.protobuf.AbstractParser<AddGroupMemberRequest>() {\n      public AddGroupMemberRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new AddGroupMemberRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<AddGroupMemberRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string group_id = 1;\n    public static final int GROUP_ID_FIELD_NUMBER = 1;\n    private java.lang.Object groupId_;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public boolean hasGroupId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public java.lang.String getGroupId() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          groupId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getGroupIdBytes() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        groupId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // repeated .GroupMember added_member = 2;\n    public static final int ADDED_MEMBER_FIELD_NUMBER = 2;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> addedMember_;\n    /**\n     * <code>repeated .GroupMember added_member = 2;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> getAddedMemberList() {\n      return addedMember_;\n    }\n    /**\n     * <code>repeated .GroupMember added_member = 2;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> \n        getAddedMemberOrBuilderList() {\n      return addedMember_;\n    }\n    /**\n     * <code>repeated .GroupMember added_member = 2;</code>\n     */\n    public int getAddedMemberCount() {\n      return addedMember_.size();\n    }\n    /**\n     * <code>repeated .GroupMember added_member = 2;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.GroupMember getAddedMember(int index) {\n      return addedMember_.get(index);\n    }\n    /**\n     * <code>repeated .GroupMember added_member = 2;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder getAddedMemberOrBuilder(\n        int index) {\n      return addedMember_.get(index);\n    }\n\n    // repeated int32 to_line = 3;\n    public static final int TO_LINE_FIELD_NUMBER = 3;\n    private java.util.List<java.lang.Integer> toLine_;\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    public java.util.List<java.lang.Integer>\n        getToLineList() {\n      return toLine_;\n    }\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    public int getToLineCount() {\n      return toLine_.size();\n    }\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    public int getToLine(int index) {\n      return toLine_.get(index);\n    }\n\n    // optional .MessageContent notify_content = 4;\n    public static final int NOTIFY_CONTENT_FIELD_NUMBER = 4;\n    private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_;\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    public boolean hasNotifyContent() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n      return notifyContent_;\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n      return notifyContent_;\n    }\n\n    // optional string extra = 5;\n    public static final int EXTRA_FIELD_NUMBER = 5;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 5;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string extra = 5;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 5;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      groupId_ = \"\";\n      addedMember_ = java.util.Collections.emptyList();\n      toLine_ = java.util.Collections.emptyList();\n      notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      extra_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasGroupId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      for (int i = 0; i < getAddedMemberCount(); i++) {\n        if (!getAddedMember(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      if (hasNotifyContent()) {\n        if (!getNotifyContent().isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getGroupIdBytes());\n      }\n      for (int i = 0; i < addedMember_.size(); i++) {\n        output.writeMessage(2, addedMember_.get(i));\n      }\n      for (int i = 0; i < toLine_.size(); i++) {\n        output.writeInt32(3, toLine_.get(i));\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeMessage(4, notifyContent_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(5, getExtraBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getGroupIdBytes());\n      }\n      for (int i = 0; i < addedMember_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(2, addedMember_.get(i));\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < toLine_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeInt32SizeNoTag(toLine_.get(i));\n        }\n        size += dataSize;\n        size += 1 * getToLineList().size();\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(4, notifyContent_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5, getExtraBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code AddGroupMemberRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_AddGroupMemberRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_AddGroupMemberRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest.class, cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getAddedMemberFieldBuilder();\n          getNotifyContentFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        groupId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        if (addedMemberBuilder_ == null) {\n          addedMember_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000002);\n        } else {\n          addedMemberBuilder_.clear();\n        }\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000004);\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000008);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000010);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_AddGroupMemberRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest build() {\n        cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest result = new cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.groupId_ = groupId_;\n        if (addedMemberBuilder_ == null) {\n          if (((bitField0_ & 0x00000002) == 0x00000002)) {\n            addedMember_ = java.util.Collections.unmodifiableList(addedMember_);\n            bitField0_ = (bitField0_ & ~0x00000002);\n          }\n          result.addedMember_ = addedMember_;\n        } else {\n          result.addedMember_ = addedMemberBuilder_.build();\n        }\n        if (((bitField0_ & 0x00000004) == 0x00000004)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n          bitField0_ = (bitField0_ & ~0x00000004);\n        }\n        result.toLine_ = toLine_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        if (notifyContentBuilder_ == null) {\n          result.notifyContent_ = notifyContent_;\n        } else {\n          result.notifyContent_ = notifyContentBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.extra_ = extra_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest.getDefaultInstance()) return this;\n        if (other.hasGroupId()) {\n          bitField0_ |= 0x00000001;\n          groupId_ = other.groupId_;\n          onChanged();\n        }\n        if (addedMemberBuilder_ == null) {\n          if (!other.addedMember_.isEmpty()) {\n            if (addedMember_.isEmpty()) {\n              addedMember_ = other.addedMember_;\n              bitField0_ = (bitField0_ & ~0x00000002);\n            } else {\n              ensureAddedMemberIsMutable();\n              addedMember_.addAll(other.addedMember_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.addedMember_.isEmpty()) {\n            if (addedMemberBuilder_.isEmpty()) {\n              addedMemberBuilder_.dispose();\n              addedMemberBuilder_ = null;\n              addedMember_ = other.addedMember_;\n              bitField0_ = (bitField0_ & ~0x00000002);\n              addedMemberBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getAddedMemberFieldBuilder() : null;\n            } else {\n              addedMemberBuilder_.addAllMessages(other.addedMember_);\n            }\n          }\n        }\n        if (!other.toLine_.isEmpty()) {\n          if (toLine_.isEmpty()) {\n            toLine_ = other.toLine_;\n            bitField0_ = (bitField0_ & ~0x00000004);\n          } else {\n            ensureToLineIsMutable();\n            toLine_.addAll(other.toLine_);\n          }\n          onChanged();\n        }\n        if (other.hasNotifyContent()) {\n          mergeNotifyContent(other.getNotifyContent());\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000010;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasGroupId()) {\n          \n          return false;\n        }\n        for (int i = 0; i < getAddedMemberCount(); i++) {\n          if (!getAddedMember(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        if (hasNotifyContent()) {\n          if (!getNotifyContent().isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.AddGroupMemberRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string group_id = 1;\n      private java.lang.Object groupId_ = \"\";\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public boolean hasGroupId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public java.lang.String getGroupId() {\n        java.lang.Object ref = groupId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          groupId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getGroupIdBytes() {\n        java.lang.Object ref = groupId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          groupId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder clearGroupId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        groupId_ = getDefaultInstance().getGroupId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // repeated .GroupMember added_member = 2;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> addedMember_ =\n        java.util.Collections.emptyList();\n      private void ensureAddedMemberIsMutable() {\n        if (!((bitField0_ & 0x00000002) == 0x00000002)) {\n          addedMember_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.GroupMember>(addedMember_);\n          bitField0_ |= 0x00000002;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.GroupMember, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder, cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> addedMemberBuilder_;\n\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> getAddedMemberList() {\n        if (addedMemberBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(addedMember_);\n        } else {\n          return addedMemberBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public int getAddedMemberCount() {\n        if (addedMemberBuilder_ == null) {\n          return addedMember_.size();\n        } else {\n          return addedMemberBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMember getAddedMember(int index) {\n        if (addedMemberBuilder_ == null) {\n          return addedMember_.get(index);\n        } else {\n          return addedMemberBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public Builder setAddedMember(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupMember value) {\n        if (addedMemberBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureAddedMemberIsMutable();\n          addedMember_.set(index, value);\n          onChanged();\n        } else {\n          addedMemberBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public Builder setAddedMember(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder builderForValue) {\n        if (addedMemberBuilder_ == null) {\n          ensureAddedMemberIsMutable();\n          addedMember_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          addedMemberBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public Builder addAddedMember(cn.wildfirechat.proto.WFCMessage.GroupMember value) {\n        if (addedMemberBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureAddedMemberIsMutable();\n          addedMember_.add(value);\n          onChanged();\n        } else {\n          addedMemberBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public Builder addAddedMember(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupMember value) {\n        if (addedMemberBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureAddedMemberIsMutable();\n          addedMember_.add(index, value);\n          onChanged();\n        } else {\n          addedMemberBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public Builder addAddedMember(\n          cn.wildfirechat.proto.WFCMessage.GroupMember.Builder builderForValue) {\n        if (addedMemberBuilder_ == null) {\n          ensureAddedMemberIsMutable();\n          addedMember_.add(builderForValue.build());\n          onChanged();\n        } else {\n          addedMemberBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public Builder addAddedMember(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder builderForValue) {\n        if (addedMemberBuilder_ == null) {\n          ensureAddedMemberIsMutable();\n          addedMember_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          addedMemberBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public Builder addAllAddedMember(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.GroupMember> values) {\n        if (addedMemberBuilder_ == null) {\n          ensureAddedMemberIsMutable();\n          super.addAll(values, addedMember_);\n          onChanged();\n        } else {\n          addedMemberBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public Builder clearAddedMember() {\n        if (addedMemberBuilder_ == null) {\n          addedMember_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000002);\n          onChanged();\n        } else {\n          addedMemberBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public Builder removeAddedMember(int index) {\n        if (addedMemberBuilder_ == null) {\n          ensureAddedMemberIsMutable();\n          addedMember_.remove(index);\n          onChanged();\n        } else {\n          addedMemberBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMember.Builder getAddedMemberBuilder(\n          int index) {\n        return getAddedMemberFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder getAddedMemberOrBuilder(\n          int index) {\n        if (addedMemberBuilder_ == null) {\n          return addedMember_.get(index);  } else {\n          return addedMemberBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> \n           getAddedMemberOrBuilderList() {\n        if (addedMemberBuilder_ != null) {\n          return addedMemberBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(addedMember_);\n        }\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMember.Builder addAddedMemberBuilder() {\n        return getAddedMemberFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.GroupMember.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMember.Builder addAddedMemberBuilder(\n          int index) {\n        return getAddedMemberFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.GroupMember.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .GroupMember added_member = 2;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember.Builder> \n           getAddedMemberBuilderList() {\n        return getAddedMemberFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.GroupMember, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder, cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> \n          getAddedMemberFieldBuilder() {\n        if (addedMemberBuilder_ == null) {\n          addedMemberBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.GroupMember, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder, cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder>(\n                  addedMember_,\n                  ((bitField0_ & 0x00000002) == 0x00000002),\n                  getParentForChildren(),\n                  isClean());\n          addedMember_ = null;\n        }\n        return addedMemberBuilder_;\n      }\n\n      // repeated int32 to_line = 3;\n      private java.util.List<java.lang.Integer> toLine_ = java.util.Collections.emptyList();\n      private void ensureToLineIsMutable() {\n        if (!((bitField0_ & 0x00000004) == 0x00000004)) {\n          toLine_ = new java.util.ArrayList<java.lang.Integer>(toLine_);\n          bitField0_ |= 0x00000004;\n         }\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public java.util.List<java.lang.Integer>\n          getToLineList() {\n        return java.util.Collections.unmodifiableList(toLine_);\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public int getToLineCount() {\n        return toLine_.size();\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public int getToLine(int index) {\n        return toLine_.get(index);\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder setToLine(\n          int index, int value) {\n        ensureToLineIsMutable();\n        toLine_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder addToLine(int value) {\n        ensureToLineIsMutable();\n        toLine_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder addAllToLine(\n          java.lang.Iterable<? extends java.lang.Integer> values) {\n        ensureToLineIsMutable();\n        super.addAll(values, toLine_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder clearToLine() {\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000004);\n        onChanged();\n        return this;\n      }\n\n      // optional .MessageContent notify_content = 4;\n      private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> notifyContentBuilder_;\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public boolean hasNotifyContent() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          return notifyContent_;\n        } else {\n          return notifyContentBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder setNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          notifyContent_ = value;\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000008;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder setNotifyContent(\n          cn.wildfirechat.proto.WFCMessage.MessageContent.Builder builderForValue) {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = builderForValue.build();\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000008;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder mergeNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (((bitField0_ & 0x00000008) == 0x00000008) &&\n              notifyContent_ != cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) {\n            notifyContent_ =\n              cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder(notifyContent_).mergeFrom(value).buildPartial();\n          } else {\n            notifyContent_ = value;\n          }\n          onChanged();\n        } else {\n          notifyContentBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000008;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder clearNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n          onChanged();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent.Builder getNotifyContentBuilder() {\n        bitField0_ |= 0x00000008;\n        onChanged();\n        return getNotifyContentFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n        if (notifyContentBuilder_ != null) {\n          return notifyContentBuilder_.getMessageOrBuilder();\n        } else {\n          return notifyContent_;\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> \n          getNotifyContentFieldBuilder() {\n        if (notifyContentBuilder_ == null) {\n          notifyContentBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder>(\n                  notifyContent_,\n                  getParentForChildren(),\n                  isClean());\n          notifyContent_ = null;\n        }\n        return notifyContentBuilder_;\n      }\n\n      // optional string extra = 5;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 5;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional string extra = 5;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 5;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 5;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 5;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 5;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:AddGroupMemberRequest)\n    }\n\n    static {\n      defaultInstance = new AddGroupMemberRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:AddGroupMemberRequest)\n  }\n\n  public interface CreateGroupRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required .Group group = 1;\n    /**\n     * <code>required .Group group = 1;</code>\n     */\n    boolean hasGroup();\n    /**\n     * <code>required .Group group = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.Group getGroup();\n    /**\n     * <code>required .Group group = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.GroupOrBuilder getGroupOrBuilder();\n\n    // repeated int32 to_line = 2;\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    java.util.List<java.lang.Integer> getToLineList();\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    int getToLineCount();\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    int getToLine(int index);\n\n    // optional .MessageContent notify_content = 3;\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    boolean hasNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder();\n\n    // optional string member_extra = 4;\n    /**\n     * <code>optional string member_extra = 4;</code>\n     */\n    boolean hasMemberExtra();\n    /**\n     * <code>optional string member_extra = 4;</code>\n     */\n    java.lang.String getMemberExtra();\n    /**\n     * <code>optional string member_extra = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getMemberExtraBytes();\n  }\n  /**\n   * Protobuf type {@code CreateGroupRequest}\n   */\n  public static final class CreateGroupRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements CreateGroupRequestOrBuilder {\n    // Use CreateGroupRequest.newBuilder() to construct.\n    private CreateGroupRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private CreateGroupRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final CreateGroupRequest defaultInstance;\n    public static CreateGroupRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public CreateGroupRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private CreateGroupRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              cn.wildfirechat.proto.WFCMessage.Group.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                subBuilder = group_.toBuilder();\n              }\n              group_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.Group.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(group_);\n                group_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000001;\n              break;\n            }\n            case 16: {\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              toLine_.add(input.readInt32());\n              break;\n            }\n            case 18: {\n              int length = input.readRawVarint32();\n              int limit = input.pushLimit(length);\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002) && input.getBytesUntilLimit() > 0) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              while (input.getBytesUntilLimit() > 0) {\n                toLine_.add(input.readInt32());\n              }\n              input.popLimit(limit);\n              break;\n            }\n            case 26: {\n              cn.wildfirechat.proto.WFCMessage.MessageContent.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                subBuilder = notifyContent_.toBuilder();\n              }\n              notifyContent_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.MessageContent.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(notifyContent_);\n                notifyContent_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000002;\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000004;\n              memberExtra_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_CreateGroupRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_CreateGroupRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.CreateGroupRequest.class, cn.wildfirechat.proto.WFCMessage.CreateGroupRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<CreateGroupRequest> PARSER =\n        new com.google.protobuf.AbstractParser<CreateGroupRequest>() {\n      public CreateGroupRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new CreateGroupRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<CreateGroupRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required .Group group = 1;\n    public static final int GROUP_FIELD_NUMBER = 1;\n    private cn.wildfirechat.proto.WFCMessage.Group group_;\n    /**\n     * <code>required .Group group = 1;</code>\n     */\n    public boolean hasGroup() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required .Group group = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.Group getGroup() {\n      return group_;\n    }\n    /**\n     * <code>required .Group group = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.GroupOrBuilder getGroupOrBuilder() {\n      return group_;\n    }\n\n    // repeated int32 to_line = 2;\n    public static final int TO_LINE_FIELD_NUMBER = 2;\n    private java.util.List<java.lang.Integer> toLine_;\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    public java.util.List<java.lang.Integer>\n        getToLineList() {\n      return toLine_;\n    }\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    public int getToLineCount() {\n      return toLine_.size();\n    }\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    public int getToLine(int index) {\n      return toLine_.get(index);\n    }\n\n    // optional .MessageContent notify_content = 3;\n    public static final int NOTIFY_CONTENT_FIELD_NUMBER = 3;\n    private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_;\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    public boolean hasNotifyContent() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n      return notifyContent_;\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n      return notifyContent_;\n    }\n\n    // optional string member_extra = 4;\n    public static final int MEMBER_EXTRA_FIELD_NUMBER = 4;\n    private java.lang.Object memberExtra_;\n    /**\n     * <code>optional string member_extra = 4;</code>\n     */\n    public boolean hasMemberExtra() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string member_extra = 4;</code>\n     */\n    public java.lang.String getMemberExtra() {\n      java.lang.Object ref = memberExtra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          memberExtra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string member_extra = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getMemberExtraBytes() {\n      java.lang.Object ref = memberExtra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        memberExtra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      group_ = cn.wildfirechat.proto.WFCMessage.Group.getDefaultInstance();\n      toLine_ = java.util.Collections.emptyList();\n      notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      memberExtra_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasGroup()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!getGroup().isInitialized()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (hasNotifyContent()) {\n        if (!getNotifyContent().isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeMessage(1, group_);\n      }\n      for (int i = 0; i < toLine_.size(); i++) {\n        output.writeInt32(2, toLine_.get(i));\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeMessage(3, notifyContent_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(4, getMemberExtraBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, group_);\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < toLine_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeInt32SizeNoTag(toLine_.get(i));\n        }\n        size += dataSize;\n        size += 1 * getToLineList().size();\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(3, notifyContent_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, getMemberExtraBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.CreateGroupRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.CreateGroupRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.CreateGroupRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.CreateGroupRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.CreateGroupRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.CreateGroupRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.CreateGroupRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.CreateGroupRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.CreateGroupRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.CreateGroupRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.CreateGroupRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code CreateGroupRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.CreateGroupRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_CreateGroupRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_CreateGroupRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.CreateGroupRequest.class, cn.wildfirechat.proto.WFCMessage.CreateGroupRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.CreateGroupRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getGroupFieldBuilder();\n          getNotifyContentFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (groupBuilder_ == null) {\n          group_ = cn.wildfirechat.proto.WFCMessage.Group.getDefaultInstance();\n        } else {\n          groupBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000001);\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000002);\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000004);\n        memberExtra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_CreateGroupRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.CreateGroupRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.CreateGroupRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.CreateGroupRequest build() {\n        cn.wildfirechat.proto.WFCMessage.CreateGroupRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.CreateGroupRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.CreateGroupRequest result = new cn.wildfirechat.proto.WFCMessage.CreateGroupRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        if (groupBuilder_ == null) {\n          result.group_ = group_;\n        } else {\n          result.group_ = groupBuilder_.build();\n        }\n        if (((bitField0_ & 0x00000002) == 0x00000002)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n          bitField0_ = (bitField0_ & ~0x00000002);\n        }\n        result.toLine_ = toLine_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        if (notifyContentBuilder_ == null) {\n          result.notifyContent_ = notifyContent_;\n        } else {\n          result.notifyContent_ = notifyContentBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.memberExtra_ = memberExtra_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.CreateGroupRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.CreateGroupRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.CreateGroupRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.CreateGroupRequest.getDefaultInstance()) return this;\n        if (other.hasGroup()) {\n          mergeGroup(other.getGroup());\n        }\n        if (!other.toLine_.isEmpty()) {\n          if (toLine_.isEmpty()) {\n            toLine_ = other.toLine_;\n            bitField0_ = (bitField0_ & ~0x00000002);\n          } else {\n            ensureToLineIsMutable();\n            toLine_.addAll(other.toLine_);\n          }\n          onChanged();\n        }\n        if (other.hasNotifyContent()) {\n          mergeNotifyContent(other.getNotifyContent());\n        }\n        if (other.hasMemberExtra()) {\n          bitField0_ |= 0x00000008;\n          memberExtra_ = other.memberExtra_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasGroup()) {\n          \n          return false;\n        }\n        if (!getGroup().isInitialized()) {\n          \n          return false;\n        }\n        if (hasNotifyContent()) {\n          if (!getNotifyContent().isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.CreateGroupRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.CreateGroupRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required .Group group = 1;\n      private cn.wildfirechat.proto.WFCMessage.Group group_ = cn.wildfirechat.proto.WFCMessage.Group.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.Group, cn.wildfirechat.proto.WFCMessage.Group.Builder, cn.wildfirechat.proto.WFCMessage.GroupOrBuilder> groupBuilder_;\n      /**\n       * <code>required .Group group = 1;</code>\n       */\n      public boolean hasGroup() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required .Group group = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Group getGroup() {\n        if (groupBuilder_ == null) {\n          return group_;\n        } else {\n          return groupBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>required .Group group = 1;</code>\n       */\n      public Builder setGroup(cn.wildfirechat.proto.WFCMessage.Group value) {\n        if (groupBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          group_ = value;\n          onChanged();\n        } else {\n          groupBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .Group group = 1;</code>\n       */\n      public Builder setGroup(\n          cn.wildfirechat.proto.WFCMessage.Group.Builder builderForValue) {\n        if (groupBuilder_ == null) {\n          group_ = builderForValue.build();\n          onChanged();\n        } else {\n          groupBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .Group group = 1;</code>\n       */\n      public Builder mergeGroup(cn.wildfirechat.proto.WFCMessage.Group value) {\n        if (groupBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001) &&\n              group_ != cn.wildfirechat.proto.WFCMessage.Group.getDefaultInstance()) {\n            group_ =\n              cn.wildfirechat.proto.WFCMessage.Group.newBuilder(group_).mergeFrom(value).buildPartial();\n          } else {\n            group_ = value;\n          }\n          onChanged();\n        } else {\n          groupBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .Group group = 1;</code>\n       */\n      public Builder clearGroup() {\n        if (groupBuilder_ == null) {\n          group_ = cn.wildfirechat.proto.WFCMessage.Group.getDefaultInstance();\n          onChanged();\n        } else {\n          groupBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000001);\n        return this;\n      }\n      /**\n       * <code>required .Group group = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Group.Builder getGroupBuilder() {\n        bitField0_ |= 0x00000001;\n        onChanged();\n        return getGroupFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>required .Group group = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupOrBuilder getGroupOrBuilder() {\n        if (groupBuilder_ != null) {\n          return groupBuilder_.getMessageOrBuilder();\n        } else {\n          return group_;\n        }\n      }\n      /**\n       * <code>required .Group group = 1;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.Group, cn.wildfirechat.proto.WFCMessage.Group.Builder, cn.wildfirechat.proto.WFCMessage.GroupOrBuilder> \n          getGroupFieldBuilder() {\n        if (groupBuilder_ == null) {\n          groupBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.Group, cn.wildfirechat.proto.WFCMessage.Group.Builder, cn.wildfirechat.proto.WFCMessage.GroupOrBuilder>(\n                  group_,\n                  getParentForChildren(),\n                  isClean());\n          group_ = null;\n        }\n        return groupBuilder_;\n      }\n\n      // repeated int32 to_line = 2;\n      private java.util.List<java.lang.Integer> toLine_ = java.util.Collections.emptyList();\n      private void ensureToLineIsMutable() {\n        if (!((bitField0_ & 0x00000002) == 0x00000002)) {\n          toLine_ = new java.util.ArrayList<java.lang.Integer>(toLine_);\n          bitField0_ |= 0x00000002;\n         }\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public java.util.List<java.lang.Integer>\n          getToLineList() {\n        return java.util.Collections.unmodifiableList(toLine_);\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public int getToLineCount() {\n        return toLine_.size();\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public int getToLine(int index) {\n        return toLine_.get(index);\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder setToLine(\n          int index, int value) {\n        ensureToLineIsMutable();\n        toLine_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder addToLine(int value) {\n        ensureToLineIsMutable();\n        toLine_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder addAllToLine(\n          java.lang.Iterable<? extends java.lang.Integer> values) {\n        ensureToLineIsMutable();\n        super.addAll(values, toLine_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder clearToLine() {\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000002);\n        onChanged();\n        return this;\n      }\n\n      // optional .MessageContent notify_content = 3;\n      private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> notifyContentBuilder_;\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public boolean hasNotifyContent() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          return notifyContent_;\n        } else {\n          return notifyContentBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder setNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          notifyContent_ = value;\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder setNotifyContent(\n          cn.wildfirechat.proto.WFCMessage.MessageContent.Builder builderForValue) {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = builderForValue.build();\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder mergeNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (((bitField0_ & 0x00000004) == 0x00000004) &&\n              notifyContent_ != cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) {\n            notifyContent_ =\n              cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder(notifyContent_).mergeFrom(value).buildPartial();\n          } else {\n            notifyContent_ = value;\n          }\n          onChanged();\n        } else {\n          notifyContentBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder clearNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n          onChanged();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent.Builder getNotifyContentBuilder() {\n        bitField0_ |= 0x00000004;\n        onChanged();\n        return getNotifyContentFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n        if (notifyContentBuilder_ != null) {\n          return notifyContentBuilder_.getMessageOrBuilder();\n        } else {\n          return notifyContent_;\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> \n          getNotifyContentFieldBuilder() {\n        if (notifyContentBuilder_ == null) {\n          notifyContentBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder>(\n                  notifyContent_,\n                  getParentForChildren(),\n                  isClean());\n          notifyContent_ = null;\n        }\n        return notifyContentBuilder_;\n      }\n\n      // optional string member_extra = 4;\n      private java.lang.Object memberExtra_ = \"\";\n      /**\n       * <code>optional string member_extra = 4;</code>\n       */\n      public boolean hasMemberExtra() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional string member_extra = 4;</code>\n       */\n      public java.lang.String getMemberExtra() {\n        java.lang.Object ref = memberExtra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          memberExtra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string member_extra = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getMemberExtraBytes() {\n        java.lang.Object ref = memberExtra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          memberExtra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string member_extra = 4;</code>\n       */\n      public Builder setMemberExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        memberExtra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string member_extra = 4;</code>\n       */\n      public Builder clearMemberExtra() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        memberExtra_ = getDefaultInstance().getMemberExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string member_extra = 4;</code>\n       */\n      public Builder setMemberExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        memberExtra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:CreateGroupRequest)\n    }\n\n    static {\n      defaultInstance = new CreateGroupRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:CreateGroupRequest)\n  }\n\n  public interface DismissGroupRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string group_id = 1;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    boolean hasGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    java.lang.String getGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getGroupIdBytes();\n\n    // repeated int32 to_line = 2;\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    java.util.List<java.lang.Integer> getToLineList();\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    int getToLineCount();\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    int getToLine(int index);\n\n    // optional .MessageContent notify_content = 3;\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    boolean hasNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder();\n  }\n  /**\n   * Protobuf type {@code DismissGroupRequest}\n   */\n  public static final class DismissGroupRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements DismissGroupRequestOrBuilder {\n    // Use DismissGroupRequest.newBuilder() to construct.\n    private DismissGroupRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private DismissGroupRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final DismissGroupRequest defaultInstance;\n    public static DismissGroupRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public DismissGroupRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private DismissGroupRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              groupId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              toLine_.add(input.readInt32());\n              break;\n            }\n            case 18: {\n              int length = input.readRawVarint32();\n              int limit = input.pushLimit(length);\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002) && input.getBytesUntilLimit() > 0) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              while (input.getBytesUntilLimit() > 0) {\n                toLine_.add(input.readInt32());\n              }\n              input.popLimit(limit);\n              break;\n            }\n            case 26: {\n              cn.wildfirechat.proto.WFCMessage.MessageContent.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                subBuilder = notifyContent_.toBuilder();\n              }\n              notifyContent_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.MessageContent.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(notifyContent_);\n                notifyContent_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000002;\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_DismissGroupRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_DismissGroupRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.DismissGroupRequest.class, cn.wildfirechat.proto.WFCMessage.DismissGroupRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<DismissGroupRequest> PARSER =\n        new com.google.protobuf.AbstractParser<DismissGroupRequest>() {\n      public DismissGroupRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new DismissGroupRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<DismissGroupRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string group_id = 1;\n    public static final int GROUP_ID_FIELD_NUMBER = 1;\n    private java.lang.Object groupId_;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public boolean hasGroupId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public java.lang.String getGroupId() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          groupId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getGroupIdBytes() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        groupId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // repeated int32 to_line = 2;\n    public static final int TO_LINE_FIELD_NUMBER = 2;\n    private java.util.List<java.lang.Integer> toLine_;\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    public java.util.List<java.lang.Integer>\n        getToLineList() {\n      return toLine_;\n    }\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    public int getToLineCount() {\n      return toLine_.size();\n    }\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    public int getToLine(int index) {\n      return toLine_.get(index);\n    }\n\n    // optional .MessageContent notify_content = 3;\n    public static final int NOTIFY_CONTENT_FIELD_NUMBER = 3;\n    private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_;\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    public boolean hasNotifyContent() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n      return notifyContent_;\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n      return notifyContent_;\n    }\n\n    private void initFields() {\n      groupId_ = \"\";\n      toLine_ = java.util.Collections.emptyList();\n      notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasGroupId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (hasNotifyContent()) {\n        if (!getNotifyContent().isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getGroupIdBytes());\n      }\n      for (int i = 0; i < toLine_.size(); i++) {\n        output.writeInt32(2, toLine_.get(i));\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeMessage(3, notifyContent_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getGroupIdBytes());\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < toLine_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeInt32SizeNoTag(toLine_.get(i));\n        }\n        size += dataSize;\n        size += 1 * getToLineList().size();\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(3, notifyContent_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.DismissGroupRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.DismissGroupRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.DismissGroupRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.DismissGroupRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.DismissGroupRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.DismissGroupRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.DismissGroupRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.DismissGroupRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.DismissGroupRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.DismissGroupRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.DismissGroupRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code DismissGroupRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.DismissGroupRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_DismissGroupRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_DismissGroupRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.DismissGroupRequest.class, cn.wildfirechat.proto.WFCMessage.DismissGroupRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.DismissGroupRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getNotifyContentFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        groupId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000002);\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_DismissGroupRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.DismissGroupRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.DismissGroupRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.DismissGroupRequest build() {\n        cn.wildfirechat.proto.WFCMessage.DismissGroupRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.DismissGroupRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.DismissGroupRequest result = new cn.wildfirechat.proto.WFCMessage.DismissGroupRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.groupId_ = groupId_;\n        if (((bitField0_ & 0x00000002) == 0x00000002)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n          bitField0_ = (bitField0_ & ~0x00000002);\n        }\n        result.toLine_ = toLine_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        if (notifyContentBuilder_ == null) {\n          result.notifyContent_ = notifyContent_;\n        } else {\n          result.notifyContent_ = notifyContentBuilder_.build();\n        }\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.DismissGroupRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.DismissGroupRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.DismissGroupRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.DismissGroupRequest.getDefaultInstance()) return this;\n        if (other.hasGroupId()) {\n          bitField0_ |= 0x00000001;\n          groupId_ = other.groupId_;\n          onChanged();\n        }\n        if (!other.toLine_.isEmpty()) {\n          if (toLine_.isEmpty()) {\n            toLine_ = other.toLine_;\n            bitField0_ = (bitField0_ & ~0x00000002);\n          } else {\n            ensureToLineIsMutable();\n            toLine_.addAll(other.toLine_);\n          }\n          onChanged();\n        }\n        if (other.hasNotifyContent()) {\n          mergeNotifyContent(other.getNotifyContent());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasGroupId()) {\n          \n          return false;\n        }\n        if (hasNotifyContent()) {\n          if (!getNotifyContent().isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.DismissGroupRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.DismissGroupRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string group_id = 1;\n      private java.lang.Object groupId_ = \"\";\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public boolean hasGroupId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public java.lang.String getGroupId() {\n        java.lang.Object ref = groupId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          groupId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getGroupIdBytes() {\n        java.lang.Object ref = groupId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          groupId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder clearGroupId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        groupId_ = getDefaultInstance().getGroupId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // repeated int32 to_line = 2;\n      private java.util.List<java.lang.Integer> toLine_ = java.util.Collections.emptyList();\n      private void ensureToLineIsMutable() {\n        if (!((bitField0_ & 0x00000002) == 0x00000002)) {\n          toLine_ = new java.util.ArrayList<java.lang.Integer>(toLine_);\n          bitField0_ |= 0x00000002;\n         }\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public java.util.List<java.lang.Integer>\n          getToLineList() {\n        return java.util.Collections.unmodifiableList(toLine_);\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public int getToLineCount() {\n        return toLine_.size();\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public int getToLine(int index) {\n        return toLine_.get(index);\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder setToLine(\n          int index, int value) {\n        ensureToLineIsMutable();\n        toLine_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder addToLine(int value) {\n        ensureToLineIsMutable();\n        toLine_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder addAllToLine(\n          java.lang.Iterable<? extends java.lang.Integer> values) {\n        ensureToLineIsMutable();\n        super.addAll(values, toLine_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder clearToLine() {\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000002);\n        onChanged();\n        return this;\n      }\n\n      // optional .MessageContent notify_content = 3;\n      private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> notifyContentBuilder_;\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public boolean hasNotifyContent() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          return notifyContent_;\n        } else {\n          return notifyContentBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder setNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          notifyContent_ = value;\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder setNotifyContent(\n          cn.wildfirechat.proto.WFCMessage.MessageContent.Builder builderForValue) {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = builderForValue.build();\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder mergeNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (((bitField0_ & 0x00000004) == 0x00000004) &&\n              notifyContent_ != cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) {\n            notifyContent_ =\n              cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder(notifyContent_).mergeFrom(value).buildPartial();\n          } else {\n            notifyContent_ = value;\n          }\n          onChanged();\n        } else {\n          notifyContentBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder clearNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n          onChanged();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent.Builder getNotifyContentBuilder() {\n        bitField0_ |= 0x00000004;\n        onChanged();\n        return getNotifyContentFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n        if (notifyContentBuilder_ != null) {\n          return notifyContentBuilder_.getMessageOrBuilder();\n        } else {\n          return notifyContent_;\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> \n          getNotifyContentFieldBuilder() {\n        if (notifyContentBuilder_ == null) {\n          notifyContentBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder>(\n                  notifyContent_,\n                  getParentForChildren(),\n                  isClean());\n          notifyContent_ = null;\n        }\n        return notifyContentBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:DismissGroupRequest)\n    }\n\n    static {\n      defaultInstance = new DismissGroupRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:DismissGroupRequest)\n  }\n\n  public interface FriendRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // optional string from_uid = 1;\n    /**\n     * <code>optional string from_uid = 1;</code>\n     */\n    boolean hasFromUid();\n    /**\n     * <code>optional string from_uid = 1;</code>\n     */\n    java.lang.String getFromUid();\n    /**\n     * <code>optional string from_uid = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getFromUidBytes();\n\n    // required string to_uid = 2;\n    /**\n     * <code>required string to_uid = 2;</code>\n     */\n    boolean hasToUid();\n    /**\n     * <code>required string to_uid = 2;</code>\n     */\n    java.lang.String getToUid();\n    /**\n     * <code>required string to_uid = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getToUidBytes();\n\n    // required string reason = 3;\n    /**\n     * <code>required string reason = 3;</code>\n     */\n    boolean hasReason();\n    /**\n     * <code>required string reason = 3;</code>\n     */\n    java.lang.String getReason();\n    /**\n     * <code>required string reason = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getReasonBytes();\n\n    // optional int32 status = 4;\n    /**\n     * <code>optional int32 status = 4;</code>\n     */\n    boolean hasStatus();\n    /**\n     * <code>optional int32 status = 4;</code>\n     */\n    int getStatus();\n\n    // optional int64 update_dt = 5;\n    /**\n     * <code>optional int64 update_dt = 5;</code>\n     */\n    boolean hasUpdateDt();\n    /**\n     * <code>optional int64 update_dt = 5;</code>\n     */\n    long getUpdateDt();\n\n    // optional bool from_read_status = 6;\n    /**\n     * <code>optional bool from_read_status = 6;</code>\n     */\n    boolean hasFromReadStatus();\n    /**\n     * <code>optional bool from_read_status = 6;</code>\n     */\n    boolean getFromReadStatus();\n\n    // optional bool to_read_status = 7;\n    /**\n     * <code>optional bool to_read_status = 7;</code>\n     */\n    boolean hasToReadStatus();\n    /**\n     * <code>optional bool to_read_status = 7;</code>\n     */\n    boolean getToReadStatus();\n\n    // optional string extra = 8;\n    /**\n     * <code>optional string extra = 8;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 8;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 8;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n  }\n  /**\n   * Protobuf type {@code FriendRequest}\n   */\n  public static final class FriendRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements FriendRequestOrBuilder {\n    // Use FriendRequest.newBuilder() to construct.\n    private FriendRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private FriendRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final FriendRequest defaultInstance;\n    public static FriendRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public FriendRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private FriendRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              fromUid_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              toUid_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              reason_ = input.readBytes();\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000008;\n              status_ = input.readInt32();\n              break;\n            }\n            case 40: {\n              bitField0_ |= 0x00000010;\n              updateDt_ = input.readInt64();\n              break;\n            }\n            case 48: {\n              bitField0_ |= 0x00000020;\n              fromReadStatus_ = input.readBool();\n              break;\n            }\n            case 56: {\n              bitField0_ |= 0x00000040;\n              toReadStatus_ = input.readBool();\n              break;\n            }\n            case 66: {\n              bitField0_ |= 0x00000080;\n              extra_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_FriendRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_FriendRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.FriendRequest.class, cn.wildfirechat.proto.WFCMessage.FriendRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<FriendRequest> PARSER =\n        new com.google.protobuf.AbstractParser<FriendRequest>() {\n      public FriendRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new FriendRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<FriendRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // optional string from_uid = 1;\n    public static final int FROM_UID_FIELD_NUMBER = 1;\n    private java.lang.Object fromUid_;\n    /**\n     * <code>optional string from_uid = 1;</code>\n     */\n    public boolean hasFromUid() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional string from_uid = 1;</code>\n     */\n    public java.lang.String getFromUid() {\n      java.lang.Object ref = fromUid_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          fromUid_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string from_uid = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getFromUidBytes() {\n      java.lang.Object ref = fromUid_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        fromUid_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string to_uid = 2;\n    public static final int TO_UID_FIELD_NUMBER = 2;\n    private java.lang.Object toUid_;\n    /**\n     * <code>required string to_uid = 2;</code>\n     */\n    public boolean hasToUid() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string to_uid = 2;</code>\n     */\n    public java.lang.String getToUid() {\n      java.lang.Object ref = toUid_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          toUid_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string to_uid = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getToUidBytes() {\n      java.lang.Object ref = toUid_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        toUid_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string reason = 3;\n    public static final int REASON_FIELD_NUMBER = 3;\n    private java.lang.Object reason_;\n    /**\n     * <code>required string reason = 3;</code>\n     */\n    public boolean hasReason() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required string reason = 3;</code>\n     */\n    public java.lang.String getReason() {\n      java.lang.Object ref = reason_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          reason_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string reason = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getReasonBytes() {\n      java.lang.Object ref = reason_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        reason_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 status = 4;\n    public static final int STATUS_FIELD_NUMBER = 4;\n    private int status_;\n    /**\n     * <code>optional int32 status = 4;</code>\n     */\n    public boolean hasStatus() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional int32 status = 4;</code>\n     */\n    public int getStatus() {\n      return status_;\n    }\n\n    // optional int64 update_dt = 5;\n    public static final int UPDATE_DT_FIELD_NUMBER = 5;\n    private long updateDt_;\n    /**\n     * <code>optional int64 update_dt = 5;</code>\n     */\n    public boolean hasUpdateDt() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional int64 update_dt = 5;</code>\n     */\n    public long getUpdateDt() {\n      return updateDt_;\n    }\n\n    // optional bool from_read_status = 6;\n    public static final int FROM_READ_STATUS_FIELD_NUMBER = 6;\n    private boolean fromReadStatus_;\n    /**\n     * <code>optional bool from_read_status = 6;</code>\n     */\n    public boolean hasFromReadStatus() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional bool from_read_status = 6;</code>\n     */\n    public boolean getFromReadStatus() {\n      return fromReadStatus_;\n    }\n\n    // optional bool to_read_status = 7;\n    public static final int TO_READ_STATUS_FIELD_NUMBER = 7;\n    private boolean toReadStatus_;\n    /**\n     * <code>optional bool to_read_status = 7;</code>\n     */\n    public boolean hasToReadStatus() {\n      return ((bitField0_ & 0x00000040) == 0x00000040);\n    }\n    /**\n     * <code>optional bool to_read_status = 7;</code>\n     */\n    public boolean getToReadStatus() {\n      return toReadStatus_;\n    }\n\n    // optional string extra = 8;\n    public static final int EXTRA_FIELD_NUMBER = 8;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 8;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000080) == 0x00000080);\n    }\n    /**\n     * <code>optional string extra = 8;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 8;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      fromUid_ = \"\";\n      toUid_ = \"\";\n      reason_ = \"\";\n      status_ = 0;\n      updateDt_ = 0L;\n      fromReadStatus_ = false;\n      toReadStatus_ = false;\n      extra_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasToUid()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasReason()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getFromUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getToUidBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getReasonBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeInt32(4, status_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeInt64(5, updateDt_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeBool(6, fromReadStatus_);\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        output.writeBool(7, toReadStatus_);\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        output.writeBytes(8, getExtraBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getFromUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getToUidBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getReasonBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(4, status_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(5, updateDt_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBoolSize(6, fromReadStatus_);\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBoolSize(7, toReadStatus_);\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(8, getExtraBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.FriendRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.FriendRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.FriendRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.FriendRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.FriendRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.FriendRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.FriendRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.FriendRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.FriendRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.FriendRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.FriendRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code FriendRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.FriendRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_FriendRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_FriendRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.FriendRequest.class, cn.wildfirechat.proto.WFCMessage.FriendRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.FriendRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        fromUid_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        toUid_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        reason_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        status_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        updateDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000010);\n        fromReadStatus_ = false;\n        bitField0_ = (bitField0_ & ~0x00000020);\n        toReadStatus_ = false;\n        bitField0_ = (bitField0_ & ~0x00000040);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000080);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_FriendRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.FriendRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.FriendRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.FriendRequest build() {\n        cn.wildfirechat.proto.WFCMessage.FriendRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.FriendRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.FriendRequest result = new cn.wildfirechat.proto.WFCMessage.FriendRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.fromUid_ = fromUid_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.toUid_ = toUid_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.reason_ = reason_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.status_ = status_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.updateDt_ = updateDt_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.fromReadStatus_ = fromReadStatus_;\n        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {\n          to_bitField0_ |= 0x00000040;\n        }\n        result.toReadStatus_ = toReadStatus_;\n        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {\n          to_bitField0_ |= 0x00000080;\n        }\n        result.extra_ = extra_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.FriendRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.FriendRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.FriendRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.FriendRequest.getDefaultInstance()) return this;\n        if (other.hasFromUid()) {\n          bitField0_ |= 0x00000001;\n          fromUid_ = other.fromUid_;\n          onChanged();\n        }\n        if (other.hasToUid()) {\n          bitField0_ |= 0x00000002;\n          toUid_ = other.toUid_;\n          onChanged();\n        }\n        if (other.hasReason()) {\n          bitField0_ |= 0x00000004;\n          reason_ = other.reason_;\n          onChanged();\n        }\n        if (other.hasStatus()) {\n          setStatus(other.getStatus());\n        }\n        if (other.hasUpdateDt()) {\n          setUpdateDt(other.getUpdateDt());\n        }\n        if (other.hasFromReadStatus()) {\n          setFromReadStatus(other.getFromReadStatus());\n        }\n        if (other.hasToReadStatus()) {\n          setToReadStatus(other.getToReadStatus());\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000080;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasToUid()) {\n          \n          return false;\n        }\n        if (!hasReason()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.FriendRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.FriendRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // optional string from_uid = 1;\n      private java.lang.Object fromUid_ = \"\";\n      /**\n       * <code>optional string from_uid = 1;</code>\n       */\n      public boolean hasFromUid() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional string from_uid = 1;</code>\n       */\n      public java.lang.String getFromUid() {\n        java.lang.Object ref = fromUid_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          fromUid_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string from_uid = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getFromUidBytes() {\n        java.lang.Object ref = fromUid_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          fromUid_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string from_uid = 1;</code>\n       */\n      public Builder setFromUid(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        fromUid_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string from_uid = 1;</code>\n       */\n      public Builder clearFromUid() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        fromUid_ = getDefaultInstance().getFromUid();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string from_uid = 1;</code>\n       */\n      public Builder setFromUidBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        fromUid_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string to_uid = 2;\n      private java.lang.Object toUid_ = \"\";\n      /**\n       * <code>required string to_uid = 2;</code>\n       */\n      public boolean hasToUid() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string to_uid = 2;</code>\n       */\n      public java.lang.String getToUid() {\n        java.lang.Object ref = toUid_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          toUid_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string to_uid = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getToUidBytes() {\n        java.lang.Object ref = toUid_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          toUid_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string to_uid = 2;</code>\n       */\n      public Builder setToUid(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        toUid_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string to_uid = 2;</code>\n       */\n      public Builder clearToUid() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        toUid_ = getDefaultInstance().getToUid();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string to_uid = 2;</code>\n       */\n      public Builder setToUidBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        toUid_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string reason = 3;\n      private java.lang.Object reason_ = \"\";\n      /**\n       * <code>required string reason = 3;</code>\n       */\n      public boolean hasReason() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required string reason = 3;</code>\n       */\n      public java.lang.String getReason() {\n        java.lang.Object ref = reason_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          reason_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string reason = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getReasonBytes() {\n        java.lang.Object ref = reason_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          reason_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string reason = 3;</code>\n       */\n      public Builder setReason(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        reason_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string reason = 3;</code>\n       */\n      public Builder clearReason() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        reason_ = getDefaultInstance().getReason();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string reason = 3;</code>\n       */\n      public Builder setReasonBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        reason_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 status = 4;\n      private int status_ ;\n      /**\n       * <code>optional int32 status = 4;</code>\n       */\n      public boolean hasStatus() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional int32 status = 4;</code>\n       */\n      public int getStatus() {\n        return status_;\n      }\n      /**\n       * <code>optional int32 status = 4;</code>\n       */\n      public Builder setStatus(int value) {\n        bitField0_ |= 0x00000008;\n        status_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 status = 4;</code>\n       */\n      public Builder clearStatus() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        status_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 update_dt = 5;\n      private long updateDt_ ;\n      /**\n       * <code>optional int64 update_dt = 5;</code>\n       */\n      public boolean hasUpdateDt() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional int64 update_dt = 5;</code>\n       */\n      public long getUpdateDt() {\n        return updateDt_;\n      }\n      /**\n       * <code>optional int64 update_dt = 5;</code>\n       */\n      public Builder setUpdateDt(long value) {\n        bitField0_ |= 0x00000010;\n        updateDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 update_dt = 5;</code>\n       */\n      public Builder clearUpdateDt() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        updateDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional bool from_read_status = 6;\n      private boolean fromReadStatus_ ;\n      /**\n       * <code>optional bool from_read_status = 6;</code>\n       */\n      public boolean hasFromReadStatus() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional bool from_read_status = 6;</code>\n       */\n      public boolean getFromReadStatus() {\n        return fromReadStatus_;\n      }\n      /**\n       * <code>optional bool from_read_status = 6;</code>\n       */\n      public Builder setFromReadStatus(boolean value) {\n        bitField0_ |= 0x00000020;\n        fromReadStatus_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional bool from_read_status = 6;</code>\n       */\n      public Builder clearFromReadStatus() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        fromReadStatus_ = false;\n        onChanged();\n        return this;\n      }\n\n      // optional bool to_read_status = 7;\n      private boolean toReadStatus_ ;\n      /**\n       * <code>optional bool to_read_status = 7;</code>\n       */\n      public boolean hasToReadStatus() {\n        return ((bitField0_ & 0x00000040) == 0x00000040);\n      }\n      /**\n       * <code>optional bool to_read_status = 7;</code>\n       */\n      public boolean getToReadStatus() {\n        return toReadStatus_;\n      }\n      /**\n       * <code>optional bool to_read_status = 7;</code>\n       */\n      public Builder setToReadStatus(boolean value) {\n        bitField0_ |= 0x00000040;\n        toReadStatus_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional bool to_read_status = 7;</code>\n       */\n      public Builder clearToReadStatus() {\n        bitField0_ = (bitField0_ & ~0x00000040);\n        toReadStatus_ = false;\n        onChanged();\n        return this;\n      }\n\n      // optional string extra = 8;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 8;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000080) == 0x00000080);\n      }\n      /**\n       * <code>optional string extra = 8;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 8;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 8;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000080;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 8;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000080);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 8;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000080;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:FriendRequest)\n    }\n\n    static {\n      defaultInstance = new FriendRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:FriendRequest)\n  }\n\n  public interface GeneralResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int32 error_code = 1;\n    /**\n     * <code>required int32 error_code = 1;</code>\n     */\n    boolean hasErrorCode();\n    /**\n     * <code>required int32 error_code = 1;</code>\n     */\n    int getErrorCode();\n  }\n  /**\n   * Protobuf type {@code GeneralResult}\n   */\n  public static final class GeneralResult extends\n      com.google.protobuf.GeneratedMessage\n      implements GeneralResultOrBuilder {\n    // Use GeneralResult.newBuilder() to construct.\n    private GeneralResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private GeneralResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final GeneralResult defaultInstance;\n    public static GeneralResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public GeneralResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private GeneralResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              errorCode_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GeneralResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GeneralResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.GeneralResult.class, cn.wildfirechat.proto.WFCMessage.GeneralResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<GeneralResult> PARSER =\n        new com.google.protobuf.AbstractParser<GeneralResult>() {\n      public GeneralResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new GeneralResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<GeneralResult> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int32 error_code = 1;\n    public static final int ERROR_CODE_FIELD_NUMBER = 1;\n    private int errorCode_;\n    /**\n     * <code>required int32 error_code = 1;</code>\n     */\n    public boolean hasErrorCode() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int32 error_code = 1;</code>\n     */\n    public int getErrorCode() {\n      return errorCode_;\n    }\n\n    private void initFields() {\n      errorCode_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasErrorCode()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, errorCode_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, errorCode_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.GeneralResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GeneralResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GeneralResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GeneralResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GeneralResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GeneralResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GeneralResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GeneralResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GeneralResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GeneralResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.GeneralResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code GeneralResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GeneralResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GeneralResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GeneralResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.GeneralResult.class, cn.wildfirechat.proto.WFCMessage.GeneralResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.GeneralResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        errorCode_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GeneralResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GeneralResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.GeneralResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GeneralResult build() {\n        cn.wildfirechat.proto.WFCMessage.GeneralResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GeneralResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.GeneralResult result = new cn.wildfirechat.proto.WFCMessage.GeneralResult(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.errorCode_ = errorCode_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.GeneralResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.GeneralResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.GeneralResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.GeneralResult.getDefaultInstance()) return this;\n        if (other.hasErrorCode()) {\n          setErrorCode(other.getErrorCode());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasErrorCode()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.GeneralResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.GeneralResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int32 error_code = 1;\n      private int errorCode_ ;\n      /**\n       * <code>required int32 error_code = 1;</code>\n       */\n      public boolean hasErrorCode() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int32 error_code = 1;</code>\n       */\n      public int getErrorCode() {\n        return errorCode_;\n      }\n      /**\n       * <code>required int32 error_code = 1;</code>\n       */\n      public Builder setErrorCode(int value) {\n        bitField0_ |= 0x00000001;\n        errorCode_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 error_code = 1;</code>\n       */\n      public Builder clearErrorCode() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        errorCode_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:GeneralResult)\n    }\n\n    static {\n      defaultInstance = new GeneralResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:GeneralResult)\n  }\n\n  public interface GetUploadTokenRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int32 media_type = 1;\n    /**\n     * <code>required int32 media_type = 1;</code>\n     */\n    boolean hasMediaType();\n    /**\n     * <code>required int32 media_type = 1;</code>\n     */\n    int getMediaType();\n\n    // required string media_path = 2;\n    /**\n     * <code>required string media_path = 2;</code>\n     */\n    boolean hasMediaPath();\n    /**\n     * <code>required string media_path = 2;</code>\n     */\n    java.lang.String getMediaPath();\n    /**\n     * <code>required string media_path = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getMediaPathBytes();\n  }\n  /**\n   * Protobuf type {@code GetUploadTokenRequest}\n   */\n  public static final class GetUploadTokenRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements GetUploadTokenRequestOrBuilder {\n    // Use GetUploadTokenRequest.newBuilder() to construct.\n    private GetUploadTokenRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private GetUploadTokenRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final GetUploadTokenRequest defaultInstance;\n    public static GetUploadTokenRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public GetUploadTokenRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private GetUploadTokenRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              mediaType_ = input.readInt32();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              mediaPath_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetUploadTokenRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetUploadTokenRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest.class, cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<GetUploadTokenRequest> PARSER =\n        new com.google.protobuf.AbstractParser<GetUploadTokenRequest>() {\n      public GetUploadTokenRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new GetUploadTokenRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<GetUploadTokenRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int32 media_type = 1;\n    public static final int MEDIA_TYPE_FIELD_NUMBER = 1;\n    private int mediaType_;\n    /**\n     * <code>required int32 media_type = 1;</code>\n     */\n    public boolean hasMediaType() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int32 media_type = 1;</code>\n     */\n    public int getMediaType() {\n      return mediaType_;\n    }\n\n    // required string media_path = 2;\n    public static final int MEDIA_PATH_FIELD_NUMBER = 2;\n    private java.lang.Object mediaPath_;\n    /**\n     * <code>required string media_path = 2;</code>\n     */\n    public boolean hasMediaPath() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string media_path = 2;</code>\n     */\n    public java.lang.String getMediaPath() {\n      java.lang.Object ref = mediaPath_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          mediaPath_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string media_path = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getMediaPathBytes() {\n      java.lang.Object ref = mediaPath_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        mediaPath_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      mediaType_ = 0;\n      mediaPath_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasMediaType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasMediaPath()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, mediaType_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getMediaPathBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, mediaType_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getMediaPathBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code GetUploadTokenRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetUploadTokenRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetUploadTokenRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest.class, cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        mediaType_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        mediaPath_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetUploadTokenRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest build() {\n        cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest result = new cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.mediaType_ = mediaType_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.mediaPath_ = mediaPath_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest.getDefaultInstance()) return this;\n        if (other.hasMediaType()) {\n          setMediaType(other.getMediaType());\n        }\n        if (other.hasMediaPath()) {\n          bitField0_ |= 0x00000002;\n          mediaPath_ = other.mediaPath_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasMediaType()) {\n          \n          return false;\n        }\n        if (!hasMediaPath()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.GetUploadTokenRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int32 media_type = 1;\n      private int mediaType_ ;\n      /**\n       * <code>required int32 media_type = 1;</code>\n       */\n      public boolean hasMediaType() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int32 media_type = 1;</code>\n       */\n      public int getMediaType() {\n        return mediaType_;\n      }\n      /**\n       * <code>required int32 media_type = 1;</code>\n       */\n      public Builder setMediaType(int value) {\n        bitField0_ |= 0x00000001;\n        mediaType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 media_type = 1;</code>\n       */\n      public Builder clearMediaType() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        mediaType_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required string media_path = 2;\n      private java.lang.Object mediaPath_ = \"\";\n      /**\n       * <code>required string media_path = 2;</code>\n       */\n      public boolean hasMediaPath() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string media_path = 2;</code>\n       */\n      public java.lang.String getMediaPath() {\n        java.lang.Object ref = mediaPath_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          mediaPath_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string media_path = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getMediaPathBytes() {\n        java.lang.Object ref = mediaPath_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          mediaPath_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string media_path = 2;</code>\n       */\n      public Builder setMediaPath(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        mediaPath_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string media_path = 2;</code>\n       */\n      public Builder clearMediaPath() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        mediaPath_ = getDefaultInstance().getMediaPath();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string media_path = 2;</code>\n       */\n      public Builder setMediaPathBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        mediaPath_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:GetUploadTokenRequest)\n    }\n\n    static {\n      defaultInstance = new GetUploadTokenRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:GetUploadTokenRequest)\n  }\n\n  public interface GetUploadTokenResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string domain = 1;\n    /**\n     * <code>required string domain = 1;</code>\n     */\n    boolean hasDomain();\n    /**\n     * <code>required string domain = 1;</code>\n     */\n    java.lang.String getDomain();\n    /**\n     * <code>required string domain = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getDomainBytes();\n\n    // required string token = 2;\n    /**\n     * <code>required string token = 2;</code>\n     */\n    boolean hasToken();\n    /**\n     * <code>required string token = 2;</code>\n     */\n    java.lang.String getToken();\n    /**\n     * <code>required string token = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getTokenBytes();\n\n    // required string server = 3;\n    /**\n     * <code>required string server = 3;</code>\n     */\n    boolean hasServer();\n    /**\n     * <code>required string server = 3;</code>\n     */\n    java.lang.String getServer();\n    /**\n     * <code>required string server = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getServerBytes();\n\n    // optional int32 port = 4;\n    /**\n     * <code>optional int32 port = 4;</code>\n     */\n    boolean hasPort();\n    /**\n     * <code>optional int32 port = 4;</code>\n     */\n    int getPort();\n  }\n  /**\n   * Protobuf type {@code GetUploadTokenResult}\n   */\n  public static final class GetUploadTokenResult extends\n      com.google.protobuf.GeneratedMessage\n      implements GetUploadTokenResultOrBuilder {\n    // Use GetUploadTokenResult.newBuilder() to construct.\n    private GetUploadTokenResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private GetUploadTokenResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final GetUploadTokenResult defaultInstance;\n    public static GetUploadTokenResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public GetUploadTokenResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private GetUploadTokenResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              domain_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              token_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              server_ = input.readBytes();\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000008;\n              port_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetUploadTokenResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetUploadTokenResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult.class, cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<GetUploadTokenResult> PARSER =\n        new com.google.protobuf.AbstractParser<GetUploadTokenResult>() {\n      public GetUploadTokenResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new GetUploadTokenResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<GetUploadTokenResult> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string domain = 1;\n    public static final int DOMAIN_FIELD_NUMBER = 1;\n    private java.lang.Object domain_;\n    /**\n     * <code>required string domain = 1;</code>\n     */\n    public boolean hasDomain() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string domain = 1;</code>\n     */\n    public java.lang.String getDomain() {\n      java.lang.Object ref = domain_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          domain_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string domain = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDomainBytes() {\n      java.lang.Object ref = domain_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        domain_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string token = 2;\n    public static final int TOKEN_FIELD_NUMBER = 2;\n    private java.lang.Object token_;\n    /**\n     * <code>required string token = 2;</code>\n     */\n    public boolean hasToken() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string token = 2;</code>\n     */\n    public java.lang.String getToken() {\n      java.lang.Object ref = token_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          token_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string token = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTokenBytes() {\n      java.lang.Object ref = token_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        token_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string server = 3;\n    public static final int SERVER_FIELD_NUMBER = 3;\n    private java.lang.Object server_;\n    /**\n     * <code>required string server = 3;</code>\n     */\n    public boolean hasServer() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required string server = 3;</code>\n     */\n    public java.lang.String getServer() {\n      java.lang.Object ref = server_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          server_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string server = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getServerBytes() {\n      java.lang.Object ref = server_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        server_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 port = 4;\n    public static final int PORT_FIELD_NUMBER = 4;\n    private int port_;\n    /**\n     * <code>optional int32 port = 4;</code>\n     */\n    public boolean hasPort() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional int32 port = 4;</code>\n     */\n    public int getPort() {\n      return port_;\n    }\n\n    private void initFields() {\n      domain_ = \"\";\n      token_ = \"\";\n      server_ = \"\";\n      port_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasDomain()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasToken()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasServer()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getDomainBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getTokenBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getServerBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeInt32(4, port_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getDomainBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getTokenBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getServerBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(4, port_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code GetUploadTokenResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GetUploadTokenResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetUploadTokenResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetUploadTokenResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult.class, cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        domain_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        token_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        server_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        port_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetUploadTokenResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult build() {\n        cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult result = new cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.domain_ = domain_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.token_ = token_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.server_ = server_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.port_ = port_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult.getDefaultInstance()) return this;\n        if (other.hasDomain()) {\n          bitField0_ |= 0x00000001;\n          domain_ = other.domain_;\n          onChanged();\n        }\n        if (other.hasToken()) {\n          bitField0_ |= 0x00000002;\n          token_ = other.token_;\n          onChanged();\n        }\n        if (other.hasServer()) {\n          bitField0_ |= 0x00000004;\n          server_ = other.server_;\n          onChanged();\n        }\n        if (other.hasPort()) {\n          setPort(other.getPort());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasDomain()) {\n          \n          return false;\n        }\n        if (!hasToken()) {\n          \n          return false;\n        }\n        if (!hasServer()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.GetUploadTokenResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string domain = 1;\n      private java.lang.Object domain_ = \"\";\n      /**\n       * <code>required string domain = 1;</code>\n       */\n      public boolean hasDomain() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string domain = 1;</code>\n       */\n      public java.lang.String getDomain() {\n        java.lang.Object ref = domain_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          domain_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string domain = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDomainBytes() {\n        java.lang.Object ref = domain_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          domain_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string domain = 1;</code>\n       */\n      public Builder setDomain(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        domain_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string domain = 1;</code>\n       */\n      public Builder clearDomain() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        domain_ = getDefaultInstance().getDomain();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string domain = 1;</code>\n       */\n      public Builder setDomainBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        domain_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string token = 2;\n      private java.lang.Object token_ = \"\";\n      /**\n       * <code>required string token = 2;</code>\n       */\n      public boolean hasToken() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string token = 2;</code>\n       */\n      public java.lang.String getToken() {\n        java.lang.Object ref = token_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          token_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string token = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTokenBytes() {\n        java.lang.Object ref = token_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          token_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string token = 2;</code>\n       */\n      public Builder setToken(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        token_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string token = 2;</code>\n       */\n      public Builder clearToken() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        token_ = getDefaultInstance().getToken();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string token = 2;</code>\n       */\n      public Builder setTokenBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        token_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string server = 3;\n      private java.lang.Object server_ = \"\";\n      /**\n       * <code>required string server = 3;</code>\n       */\n      public boolean hasServer() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required string server = 3;</code>\n       */\n      public java.lang.String getServer() {\n        java.lang.Object ref = server_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          server_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string server = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getServerBytes() {\n        java.lang.Object ref = server_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          server_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string server = 3;</code>\n       */\n      public Builder setServer(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        server_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string server = 3;</code>\n       */\n      public Builder clearServer() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        server_ = getDefaultInstance().getServer();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string server = 3;</code>\n       */\n      public Builder setServerBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        server_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 port = 4;\n      private int port_ ;\n      /**\n       * <code>optional int32 port = 4;</code>\n       */\n      public boolean hasPort() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional int32 port = 4;</code>\n       */\n      public int getPort() {\n        return port_;\n      }\n      /**\n       * <code>optional int32 port = 4;</code>\n       */\n      public Builder setPort(int value) {\n        bitField0_ |= 0x00000008;\n        port_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 port = 4;</code>\n       */\n      public Builder clearPort() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        port_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:GetUploadTokenResult)\n    }\n\n    static {\n      defaultInstance = new GetUploadTokenResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:GetUploadTokenResult)\n  }\n\n  public interface HandleFriendRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string target_uid = 1;\n    /**\n     * <code>required string target_uid = 1;</code>\n     */\n    boolean hasTargetUid();\n    /**\n     * <code>required string target_uid = 1;</code>\n     */\n    java.lang.String getTargetUid();\n    /**\n     * <code>required string target_uid = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getTargetUidBytes();\n\n    // required int32 status = 2;\n    /**\n     * <code>required int32 status = 2;</code>\n     */\n    boolean hasStatus();\n    /**\n     * <code>required int32 status = 2;</code>\n     */\n    int getStatus();\n\n    // optional string extra = 3;\n    /**\n     * <code>optional string extra = 3;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 3;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n  }\n  /**\n   * Protobuf type {@code HandleFriendRequest}\n   */\n  public static final class HandleFriendRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements HandleFriendRequestOrBuilder {\n    // Use HandleFriendRequest.newBuilder() to construct.\n    private HandleFriendRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private HandleFriendRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final HandleFriendRequest defaultInstance;\n    public static HandleFriendRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public HandleFriendRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private HandleFriendRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              targetUid_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              status_ = input.readInt32();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              extra_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_HandleFriendRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_HandleFriendRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.HandleFriendRequest.class, cn.wildfirechat.proto.WFCMessage.HandleFriendRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<HandleFriendRequest> PARSER =\n        new com.google.protobuf.AbstractParser<HandleFriendRequest>() {\n      public HandleFriendRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new HandleFriendRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<HandleFriendRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string target_uid = 1;\n    public static final int TARGET_UID_FIELD_NUMBER = 1;\n    private java.lang.Object targetUid_;\n    /**\n     * <code>required string target_uid = 1;</code>\n     */\n    public boolean hasTargetUid() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string target_uid = 1;</code>\n     */\n    public java.lang.String getTargetUid() {\n      java.lang.Object ref = targetUid_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          targetUid_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string target_uid = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTargetUidBytes() {\n      java.lang.Object ref = targetUid_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        targetUid_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 status = 2;\n    public static final int STATUS_FIELD_NUMBER = 2;\n    private int status_;\n    /**\n     * <code>required int32 status = 2;</code>\n     */\n    public boolean hasStatus() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 status = 2;</code>\n     */\n    public int getStatus() {\n      return status_;\n    }\n\n    // optional string extra = 3;\n    public static final int EXTRA_FIELD_NUMBER = 3;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 3;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string extra = 3;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      targetUid_ = \"\";\n      status_ = 0;\n      extra_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasTargetUid()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasStatus()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getTargetUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, status_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getExtraBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getTargetUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, status_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getExtraBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.HandleFriendRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.HandleFriendRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.HandleFriendRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.HandleFriendRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.HandleFriendRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.HandleFriendRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.HandleFriendRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.HandleFriendRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.HandleFriendRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.HandleFriendRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.HandleFriendRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code HandleFriendRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.HandleFriendRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_HandleFriendRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_HandleFriendRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.HandleFriendRequest.class, cn.wildfirechat.proto.WFCMessage.HandleFriendRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.HandleFriendRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        targetUid_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        status_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_HandleFriendRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.HandleFriendRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.HandleFriendRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.HandleFriendRequest build() {\n        cn.wildfirechat.proto.WFCMessage.HandleFriendRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.HandleFriendRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.HandleFriendRequest result = new cn.wildfirechat.proto.WFCMessage.HandleFriendRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.targetUid_ = targetUid_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.status_ = status_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.extra_ = extra_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.HandleFriendRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.HandleFriendRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.HandleFriendRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.HandleFriendRequest.getDefaultInstance()) return this;\n        if (other.hasTargetUid()) {\n          bitField0_ |= 0x00000001;\n          targetUid_ = other.targetUid_;\n          onChanged();\n        }\n        if (other.hasStatus()) {\n          setStatus(other.getStatus());\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000004;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasTargetUid()) {\n          \n          return false;\n        }\n        if (!hasStatus()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.HandleFriendRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.HandleFriendRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string target_uid = 1;\n      private java.lang.Object targetUid_ = \"\";\n      /**\n       * <code>required string target_uid = 1;</code>\n       */\n      public boolean hasTargetUid() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string target_uid = 1;</code>\n       */\n      public java.lang.String getTargetUid() {\n        java.lang.Object ref = targetUid_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          targetUid_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string target_uid = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTargetUidBytes() {\n        java.lang.Object ref = targetUid_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          targetUid_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string target_uid = 1;</code>\n       */\n      public Builder setTargetUid(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        targetUid_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string target_uid = 1;</code>\n       */\n      public Builder clearTargetUid() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        targetUid_ = getDefaultInstance().getTargetUid();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string target_uid = 1;</code>\n       */\n      public Builder setTargetUidBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        targetUid_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 status = 2;\n      private int status_ ;\n      /**\n       * <code>required int32 status = 2;</code>\n       */\n      public boolean hasStatus() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 status = 2;</code>\n       */\n      public int getStatus() {\n        return status_;\n      }\n      /**\n       * <code>required int32 status = 2;</code>\n       */\n      public Builder setStatus(int value) {\n        bitField0_ |= 0x00000002;\n        status_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 status = 2;</code>\n       */\n      public Builder clearStatus() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        status_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional string extra = 3;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 3;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional string extra = 3;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 3;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 3;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 3;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:HandleFriendRequest)\n    }\n\n    static {\n      defaultInstance = new HandleFriendRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:HandleFriendRequest)\n  }\n\n  public interface IDBufOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string id = 1;\n    /**\n     * <code>required string id = 1;</code>\n     */\n    boolean hasId();\n    /**\n     * <code>required string id = 1;</code>\n     */\n    java.lang.String getId();\n    /**\n     * <code>required string id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getIdBytes();\n  }\n  /**\n   * Protobuf type {@code IDBuf}\n   */\n  public static final class IDBuf extends\n      com.google.protobuf.GeneratedMessage\n      implements IDBufOrBuilder {\n    // Use IDBuf.newBuilder() to construct.\n    private IDBuf(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private IDBuf(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final IDBuf defaultInstance;\n    public static IDBuf getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public IDBuf getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private IDBuf(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              id_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_IDBuf_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_IDBuf_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.IDBuf.class, cn.wildfirechat.proto.WFCMessage.IDBuf.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<IDBuf> PARSER =\n        new com.google.protobuf.AbstractParser<IDBuf>() {\n      public IDBuf parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new IDBuf(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<IDBuf> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string id = 1;\n    public static final int ID_FIELD_NUMBER = 1;\n    private java.lang.Object id_;\n    /**\n     * <code>required string id = 1;</code>\n     */\n    public boolean hasId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string id = 1;</code>\n     */\n    public java.lang.String getId() {\n      java.lang.Object ref = id_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          id_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getIdBytes() {\n      java.lang.Object ref = id_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        id_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      id_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getIdBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getIdBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.IDBuf parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDBuf parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDBuf parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDBuf parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDBuf parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDBuf parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDBuf parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDBuf parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDBuf parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDBuf parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.IDBuf prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code IDBuf}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.IDBufOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_IDBuf_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_IDBuf_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.IDBuf.class, cn.wildfirechat.proto.WFCMessage.IDBuf.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.IDBuf.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        id_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_IDBuf_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.IDBuf getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.IDBuf.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.IDBuf build() {\n        cn.wildfirechat.proto.WFCMessage.IDBuf result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.IDBuf buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.IDBuf result = new cn.wildfirechat.proto.WFCMessage.IDBuf(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.id_ = id_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.IDBuf) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.IDBuf)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.IDBuf other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.IDBuf.getDefaultInstance()) return this;\n        if (other.hasId()) {\n          bitField0_ |= 0x00000001;\n          id_ = other.id_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasId()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.IDBuf parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.IDBuf) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string id = 1;\n      private java.lang.Object id_ = \"\";\n      /**\n       * <code>required string id = 1;</code>\n       */\n      public boolean hasId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string id = 1;</code>\n       */\n      public java.lang.String getId() {\n        java.lang.Object ref = id_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          id_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getIdBytes() {\n        java.lang.Object ref = id_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          id_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string id = 1;</code>\n       */\n      public Builder setId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        id_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string id = 1;</code>\n       */\n      public Builder clearId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        id_ = getDefaultInstance().getId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string id = 1;</code>\n       */\n      public Builder setIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        id_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:IDBuf)\n    }\n\n    static {\n      defaultInstance = new IDBuf(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:IDBuf)\n  }\n\n  public interface IDListBufOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated string id = 1;\n    /**\n     * <code>repeated string id = 1;</code>\n     */\n    java.util.List<java.lang.String>\n    getIdList();\n    /**\n     * <code>repeated string id = 1;</code>\n     */\n    int getIdCount();\n    /**\n     * <code>repeated string id = 1;</code>\n     */\n    java.lang.String getId(int index);\n    /**\n     * <code>repeated string id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getIdBytes(int index);\n  }\n  /**\n   * Protobuf type {@code IDListBuf}\n   */\n  public static final class IDListBuf extends\n      com.google.protobuf.GeneratedMessage\n      implements IDListBufOrBuilder {\n    // Use IDListBuf.newBuilder() to construct.\n    private IDListBuf(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private IDListBuf(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final IDListBuf defaultInstance;\n    public static IDListBuf getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public IDListBuf getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private IDListBuf(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                id_ = new com.google.protobuf.LazyStringArrayList();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              id_.add(input.readBytes());\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          id_ = new com.google.protobuf.UnmodifiableLazyStringList(id_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_IDListBuf_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_IDListBuf_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.IDListBuf.class, cn.wildfirechat.proto.WFCMessage.IDListBuf.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<IDListBuf> PARSER =\n        new com.google.protobuf.AbstractParser<IDListBuf>() {\n      public IDListBuf parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new IDListBuf(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<IDListBuf> getParserForType() {\n      return PARSER;\n    }\n\n    // repeated string id = 1;\n    public static final int ID_FIELD_NUMBER = 1;\n    private com.google.protobuf.LazyStringList id_;\n    /**\n     * <code>repeated string id = 1;</code>\n     */\n    public java.util.List<java.lang.String>\n        getIdList() {\n      return id_;\n    }\n    /**\n     * <code>repeated string id = 1;</code>\n     */\n    public int getIdCount() {\n      return id_.size();\n    }\n    /**\n     * <code>repeated string id = 1;</code>\n     */\n    public java.lang.String getId(int index) {\n      return id_.get(index);\n    }\n    /**\n     * <code>repeated string id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getIdBytes(int index) {\n      return id_.getByteString(index);\n    }\n\n    private void initFields() {\n      id_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < id_.size(); i++) {\n        output.writeBytes(1, id_.getByteString(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      {\n        int dataSize = 0;\n        for (int i = 0; i < id_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeBytesSizeNoTag(id_.getByteString(i));\n        }\n        size += dataSize;\n        size += 1 * getIdList().size();\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.IDListBuf parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDListBuf parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDListBuf parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDListBuf parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDListBuf parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDListBuf parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDListBuf parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDListBuf parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDListBuf parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IDListBuf parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.IDListBuf prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code IDListBuf}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.IDListBufOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_IDListBuf_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_IDListBuf_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.IDListBuf.class, cn.wildfirechat.proto.WFCMessage.IDListBuf.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.IDListBuf.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        id_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_IDListBuf_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.IDListBuf getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.IDListBuf.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.IDListBuf build() {\n        cn.wildfirechat.proto.WFCMessage.IDListBuf result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.IDListBuf buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.IDListBuf result = new cn.wildfirechat.proto.WFCMessage.IDListBuf(this);\n        int from_bitField0_ = bitField0_;\n        if (((bitField0_ & 0x00000001) == 0x00000001)) {\n          id_ = new com.google.protobuf.UnmodifiableLazyStringList(\n              id_);\n          bitField0_ = (bitField0_ & ~0x00000001);\n        }\n        result.id_ = id_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.IDListBuf) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.IDListBuf)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.IDListBuf other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.IDListBuf.getDefaultInstance()) return this;\n        if (!other.id_.isEmpty()) {\n          if (id_.isEmpty()) {\n            id_ = other.id_;\n            bitField0_ = (bitField0_ & ~0x00000001);\n          } else {\n            ensureIdIsMutable();\n            id_.addAll(other.id_);\n          }\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.IDListBuf parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.IDListBuf) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated string id = 1;\n      private com.google.protobuf.LazyStringList id_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      private void ensureIdIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          id_ = new com.google.protobuf.LazyStringArrayList(id_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n      /**\n       * <code>repeated string id = 1;</code>\n       */\n      public java.util.List<java.lang.String>\n          getIdList() {\n        return java.util.Collections.unmodifiableList(id_);\n      }\n      /**\n       * <code>repeated string id = 1;</code>\n       */\n      public int getIdCount() {\n        return id_.size();\n      }\n      /**\n       * <code>repeated string id = 1;</code>\n       */\n      public java.lang.String getId(int index) {\n        return id_.get(index);\n      }\n      /**\n       * <code>repeated string id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getIdBytes(int index) {\n        return id_.getByteString(index);\n      }\n      /**\n       * <code>repeated string id = 1;</code>\n       */\n      public Builder setId(\n          int index, java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureIdIsMutable();\n        id_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string id = 1;</code>\n       */\n      public Builder addId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureIdIsMutable();\n        id_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string id = 1;</code>\n       */\n      public Builder addAllId(\n          java.lang.Iterable<java.lang.String> values) {\n        ensureIdIsMutable();\n        super.addAll(values, id_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string id = 1;</code>\n       */\n      public Builder clearId() {\n        id_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string id = 1;</code>\n       */\n      public Builder addIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureIdIsMutable();\n        id_.add(value);\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:IDListBuf)\n    }\n\n    static {\n      defaultInstance = new IDListBuf(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:IDListBuf)\n  }\n\n  public interface MessageOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required .Conversation conversation = 1;\n    /**\n     * <code>required .Conversation conversation = 1;</code>\n     */\n    boolean hasConversation();\n    /**\n     * <code>required .Conversation conversation = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.Conversation getConversation();\n    /**\n     * <code>required .Conversation conversation = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder getConversationOrBuilder();\n\n    // required string from_user = 2;\n    /**\n     * <code>required string from_user = 2;</code>\n     */\n    boolean hasFromUser();\n    /**\n     * <code>required string from_user = 2;</code>\n     */\n    java.lang.String getFromUser();\n    /**\n     * <code>required string from_user = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getFromUserBytes();\n\n    // required .MessageContent content = 3;\n    /**\n     * <code>required .MessageContent content = 3;</code>\n     */\n    boolean hasContent();\n    /**\n     * <code>required .MessageContent content = 3;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContent getContent();\n    /**\n     * <code>required .MessageContent content = 3;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getContentOrBuilder();\n\n    // optional int64 message_id = 4;\n    /**\n     * <code>optional int64 message_id = 4;</code>\n     */\n    boolean hasMessageId();\n    /**\n     * <code>optional int64 message_id = 4;</code>\n     */\n    long getMessageId();\n\n    // optional int64 server_timestamp = 5;\n    /**\n     * <code>optional int64 server_timestamp = 5;</code>\n     */\n    boolean hasServerTimestamp();\n    /**\n     * <code>optional int64 server_timestamp = 5;</code>\n     */\n    long getServerTimestamp();\n\n    // optional string to_user = 6;\n    /**\n     * <code>optional string to_user = 6;</code>\n     *\n     * <pre>\n     *not use anymore\n     * </pre>\n     */\n    boolean hasToUser();\n    /**\n     * <code>optional string to_user = 6;</code>\n     *\n     * <pre>\n     *not use anymore\n     * </pre>\n     */\n    java.lang.String getToUser();\n    /**\n     * <code>optional string to_user = 6;</code>\n     *\n     * <pre>\n     *not use anymore\n     * </pre>\n     */\n    com.google.protobuf.ByteString\n        getToUserBytes();\n\n    // repeated string to = 7;\n    /**\n     * <code>repeated string to = 7;</code>\n     */\n    java.util.List<java.lang.String>\n    getToList();\n    /**\n     * <code>repeated string to = 7;</code>\n     */\n    int getToCount();\n    /**\n     * <code>repeated string to = 7;</code>\n     */\n    java.lang.String getTo(int index);\n    /**\n     * <code>repeated string to = 7;</code>\n     */\n    com.google.protobuf.ByteString\n        getToBytes(int index);\n  }\n  /**\n   * Protobuf type {@code Message}\n   */\n  public static final class Message extends\n      com.google.protobuf.GeneratedMessage\n      implements MessageOrBuilder {\n    // Use Message.newBuilder() to construct.\n    private Message(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private Message(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final Message defaultInstance;\n    public static Message getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public Message getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Message(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              cn.wildfirechat.proto.WFCMessage.Conversation.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                subBuilder = conversation_.toBuilder();\n              }\n              conversation_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.Conversation.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(conversation_);\n                conversation_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000001;\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              fromUser_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              cn.wildfirechat.proto.WFCMessage.MessageContent.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000004) == 0x00000004)) {\n                subBuilder = content_.toBuilder();\n              }\n              content_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.MessageContent.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(content_);\n                content_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000004;\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000008;\n              messageId_ = input.readInt64();\n              break;\n            }\n            case 40: {\n              bitField0_ |= 0x00000010;\n              serverTimestamp_ = input.readInt64();\n              break;\n            }\n            case 50: {\n              bitField0_ |= 0x00000020;\n              toUser_ = input.readBytes();\n              break;\n            }\n            case 58: {\n              if (!((mutable_bitField0_ & 0x00000040) == 0x00000040)) {\n                to_ = new com.google.protobuf.LazyStringArrayList();\n                mutable_bitField0_ |= 0x00000040;\n              }\n              to_.add(input.readBytes());\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000040) == 0x00000040)) {\n          to_ = new com.google.protobuf.UnmodifiableLazyStringList(to_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_Message_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_Message_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.Message.class, cn.wildfirechat.proto.WFCMessage.Message.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<Message> PARSER =\n        new com.google.protobuf.AbstractParser<Message>() {\n      public Message parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Message(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Message> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required .Conversation conversation = 1;\n    public static final int CONVERSATION_FIELD_NUMBER = 1;\n    private cn.wildfirechat.proto.WFCMessage.Conversation conversation_;\n    /**\n     * <code>required .Conversation conversation = 1;</code>\n     */\n    public boolean hasConversation() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required .Conversation conversation = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.Conversation getConversation() {\n      return conversation_;\n    }\n    /**\n     * <code>required .Conversation conversation = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder getConversationOrBuilder() {\n      return conversation_;\n    }\n\n    // required string from_user = 2;\n    public static final int FROM_USER_FIELD_NUMBER = 2;\n    private java.lang.Object fromUser_;\n    /**\n     * <code>required string from_user = 2;</code>\n     */\n    public boolean hasFromUser() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string from_user = 2;</code>\n     */\n    public java.lang.String getFromUser() {\n      java.lang.Object ref = fromUser_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          fromUser_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string from_user = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getFromUserBytes() {\n      java.lang.Object ref = fromUser_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        fromUser_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required .MessageContent content = 3;\n    public static final int CONTENT_FIELD_NUMBER = 3;\n    private cn.wildfirechat.proto.WFCMessage.MessageContent content_;\n    /**\n     * <code>required .MessageContent content = 3;</code>\n     */\n    public boolean hasContent() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required .MessageContent content = 3;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContent getContent() {\n      return content_;\n    }\n    /**\n     * <code>required .MessageContent content = 3;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getContentOrBuilder() {\n      return content_;\n    }\n\n    // optional int64 message_id = 4;\n    public static final int MESSAGE_ID_FIELD_NUMBER = 4;\n    private long messageId_;\n    /**\n     * <code>optional int64 message_id = 4;</code>\n     */\n    public boolean hasMessageId() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional int64 message_id = 4;</code>\n     */\n    public long getMessageId() {\n      return messageId_;\n    }\n\n    // optional int64 server_timestamp = 5;\n    public static final int SERVER_TIMESTAMP_FIELD_NUMBER = 5;\n    private long serverTimestamp_;\n    /**\n     * <code>optional int64 server_timestamp = 5;</code>\n     */\n    public boolean hasServerTimestamp() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional int64 server_timestamp = 5;</code>\n     */\n    public long getServerTimestamp() {\n      return serverTimestamp_;\n    }\n\n    // optional string to_user = 6;\n    public static final int TO_USER_FIELD_NUMBER = 6;\n    private java.lang.Object toUser_;\n    /**\n     * <code>optional string to_user = 6;</code>\n     *\n     * <pre>\n     *not use anymore\n     * </pre>\n     */\n    public boolean hasToUser() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional string to_user = 6;</code>\n     *\n     * <pre>\n     *not use anymore\n     * </pre>\n     */\n    public java.lang.String getToUser() {\n      java.lang.Object ref = toUser_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          toUser_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string to_user = 6;</code>\n     *\n     * <pre>\n     *not use anymore\n     * </pre>\n     */\n    public com.google.protobuf.ByteString\n        getToUserBytes() {\n      java.lang.Object ref = toUser_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        toUser_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // repeated string to = 7;\n    public static final int TO_FIELD_NUMBER = 7;\n    private com.google.protobuf.LazyStringList to_;\n    /**\n     * <code>repeated string to = 7;</code>\n     */\n    public java.util.List<java.lang.String>\n        getToList() {\n      return to_;\n    }\n    /**\n     * <code>repeated string to = 7;</code>\n     */\n    public int getToCount() {\n      return to_.size();\n    }\n    /**\n     * <code>repeated string to = 7;</code>\n     */\n    public java.lang.String getTo(int index) {\n      return to_.get(index);\n    }\n    /**\n     * <code>repeated string to = 7;</code>\n     */\n    public com.google.protobuf.ByteString\n        getToBytes(int index) {\n      return to_.getByteString(index);\n    }\n\n    private void initFields() {\n      conversation_ = cn.wildfirechat.proto.WFCMessage.Conversation.getDefaultInstance();\n      fromUser_ = \"\";\n      content_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      messageId_ = 0L;\n      serverTimestamp_ = 0L;\n      toUser_ = \"\";\n      to_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasConversation()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasFromUser()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasContent()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!getConversation().isInitialized()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!getContent().isInitialized()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeMessage(1, conversation_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getFromUserBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeMessage(3, content_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeInt64(4, messageId_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeInt64(5, serverTimestamp_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeBytes(6, getToUserBytes());\n      }\n      for (int i = 0; i < to_.size(); i++) {\n        output.writeBytes(7, to_.getByteString(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, conversation_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getFromUserBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(3, content_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(4, messageId_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(5, serverTimestamp_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(6, getToUserBytes());\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < to_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeBytesSizeNoTag(to_.getByteString(i));\n        }\n        size += dataSize;\n        size += 1 * getToList().size();\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.Message parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Message parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Message parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Message parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Message parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Message parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Message parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Message parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Message parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Message parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.Message prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code Message}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.MessageOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Message_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Message_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.Message.class, cn.wildfirechat.proto.WFCMessage.Message.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.Message.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getConversationFieldBuilder();\n          getContentFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (conversationBuilder_ == null) {\n          conversation_ = cn.wildfirechat.proto.WFCMessage.Conversation.getDefaultInstance();\n        } else {\n          conversationBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000001);\n        fromUser_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        if (contentBuilder_ == null) {\n          content_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n        } else {\n          contentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000004);\n        messageId_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        serverTimestamp_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000010);\n        toUser_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000020);\n        to_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000040);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Message_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Message getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.Message.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Message build() {\n        cn.wildfirechat.proto.WFCMessage.Message result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Message buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.Message result = new cn.wildfirechat.proto.WFCMessage.Message(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        if (conversationBuilder_ == null) {\n          result.conversation_ = conversation_;\n        } else {\n          result.conversation_ = conversationBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.fromUser_ = fromUser_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        if (contentBuilder_ == null) {\n          result.content_ = content_;\n        } else {\n          result.content_ = contentBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.messageId_ = messageId_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.serverTimestamp_ = serverTimestamp_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.toUser_ = toUser_;\n        if (((bitField0_ & 0x00000040) == 0x00000040)) {\n          to_ = new com.google.protobuf.UnmodifiableLazyStringList(\n              to_);\n          bitField0_ = (bitField0_ & ~0x00000040);\n        }\n        result.to_ = to_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.Message) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.Message)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.Message other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.Message.getDefaultInstance()) return this;\n        if (other.hasConversation()) {\n          mergeConversation(other.getConversation());\n        }\n        if (other.hasFromUser()) {\n          bitField0_ |= 0x00000002;\n          fromUser_ = other.fromUser_;\n          onChanged();\n        }\n        if (other.hasContent()) {\n          mergeContent(other.getContent());\n        }\n        if (other.hasMessageId()) {\n          setMessageId(other.getMessageId());\n        }\n        if (other.hasServerTimestamp()) {\n          setServerTimestamp(other.getServerTimestamp());\n        }\n        if (other.hasToUser()) {\n          bitField0_ |= 0x00000020;\n          toUser_ = other.toUser_;\n          onChanged();\n        }\n        if (!other.to_.isEmpty()) {\n          if (to_.isEmpty()) {\n            to_ = other.to_;\n            bitField0_ = (bitField0_ & ~0x00000040);\n          } else {\n            ensureToIsMutable();\n            to_.addAll(other.to_);\n          }\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasConversation()) {\n          \n          return false;\n        }\n        if (!hasFromUser()) {\n          \n          return false;\n        }\n        if (!hasContent()) {\n          \n          return false;\n        }\n        if (!getConversation().isInitialized()) {\n          \n          return false;\n        }\n        if (!getContent().isInitialized()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.Message parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.Message) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required .Conversation conversation = 1;\n      private cn.wildfirechat.proto.WFCMessage.Conversation conversation_ = cn.wildfirechat.proto.WFCMessage.Conversation.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.Conversation, cn.wildfirechat.proto.WFCMessage.Conversation.Builder, cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder> conversationBuilder_;\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public boolean hasConversation() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Conversation getConversation() {\n        if (conversationBuilder_ == null) {\n          return conversation_;\n        } else {\n          return conversationBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public Builder setConversation(cn.wildfirechat.proto.WFCMessage.Conversation value) {\n        if (conversationBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          conversation_ = value;\n          onChanged();\n        } else {\n          conversationBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public Builder setConversation(\n          cn.wildfirechat.proto.WFCMessage.Conversation.Builder builderForValue) {\n        if (conversationBuilder_ == null) {\n          conversation_ = builderForValue.build();\n          onChanged();\n        } else {\n          conversationBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public Builder mergeConversation(cn.wildfirechat.proto.WFCMessage.Conversation value) {\n        if (conversationBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001) &&\n              conversation_ != cn.wildfirechat.proto.WFCMessage.Conversation.getDefaultInstance()) {\n            conversation_ =\n              cn.wildfirechat.proto.WFCMessage.Conversation.newBuilder(conversation_).mergeFrom(value).buildPartial();\n          } else {\n            conversation_ = value;\n          }\n          onChanged();\n        } else {\n          conversationBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public Builder clearConversation() {\n        if (conversationBuilder_ == null) {\n          conversation_ = cn.wildfirechat.proto.WFCMessage.Conversation.getDefaultInstance();\n          onChanged();\n        } else {\n          conversationBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000001);\n        return this;\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Conversation.Builder getConversationBuilder() {\n        bitField0_ |= 0x00000001;\n        onChanged();\n        return getConversationFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder getConversationOrBuilder() {\n        if (conversationBuilder_ != null) {\n          return conversationBuilder_.getMessageOrBuilder();\n        } else {\n          return conversation_;\n        }\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.Conversation, cn.wildfirechat.proto.WFCMessage.Conversation.Builder, cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder> \n          getConversationFieldBuilder() {\n        if (conversationBuilder_ == null) {\n          conversationBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.Conversation, cn.wildfirechat.proto.WFCMessage.Conversation.Builder, cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder>(\n                  conversation_,\n                  getParentForChildren(),\n                  isClean());\n          conversation_ = null;\n        }\n        return conversationBuilder_;\n      }\n\n      // required string from_user = 2;\n      private java.lang.Object fromUser_ = \"\";\n      /**\n       * <code>required string from_user = 2;</code>\n       */\n      public boolean hasFromUser() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string from_user = 2;</code>\n       */\n      public java.lang.String getFromUser() {\n        java.lang.Object ref = fromUser_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          fromUser_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string from_user = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getFromUserBytes() {\n        java.lang.Object ref = fromUser_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          fromUser_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string from_user = 2;</code>\n       */\n      public Builder setFromUser(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        fromUser_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string from_user = 2;</code>\n       */\n      public Builder clearFromUser() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        fromUser_ = getDefaultInstance().getFromUser();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string from_user = 2;</code>\n       */\n      public Builder setFromUserBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        fromUser_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required .MessageContent content = 3;\n      private cn.wildfirechat.proto.WFCMessage.MessageContent content_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> contentBuilder_;\n      /**\n       * <code>required .MessageContent content = 3;</code>\n       */\n      public boolean hasContent() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required .MessageContent content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getContent() {\n        if (contentBuilder_ == null) {\n          return content_;\n        } else {\n          return contentBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>required .MessageContent content = 3;</code>\n       */\n      public Builder setContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (contentBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          content_ = value;\n          onChanged();\n        } else {\n          contentBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>required .MessageContent content = 3;</code>\n       */\n      public Builder setContent(\n          cn.wildfirechat.proto.WFCMessage.MessageContent.Builder builderForValue) {\n        if (contentBuilder_ == null) {\n          content_ = builderForValue.build();\n          onChanged();\n        } else {\n          contentBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>required .MessageContent content = 3;</code>\n       */\n      public Builder mergeContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (contentBuilder_ == null) {\n          if (((bitField0_ & 0x00000004) == 0x00000004) &&\n              content_ != cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) {\n            content_ =\n              cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder(content_).mergeFrom(value).buildPartial();\n          } else {\n            content_ = value;\n          }\n          onChanged();\n        } else {\n          contentBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>required .MessageContent content = 3;</code>\n       */\n      public Builder clearContent() {\n        if (contentBuilder_ == null) {\n          content_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n          onChanged();\n        } else {\n          contentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n      /**\n       * <code>required .MessageContent content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent.Builder getContentBuilder() {\n        bitField0_ |= 0x00000004;\n        onChanged();\n        return getContentFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>required .MessageContent content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getContentOrBuilder() {\n        if (contentBuilder_ != null) {\n          return contentBuilder_.getMessageOrBuilder();\n        } else {\n          return content_;\n        }\n      }\n      /**\n       * <code>required .MessageContent content = 3;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> \n          getContentFieldBuilder() {\n        if (contentBuilder_ == null) {\n          contentBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder>(\n                  content_,\n                  getParentForChildren(),\n                  isClean());\n          content_ = null;\n        }\n        return contentBuilder_;\n      }\n\n      // optional int64 message_id = 4;\n      private long messageId_ ;\n      /**\n       * <code>optional int64 message_id = 4;</code>\n       */\n      public boolean hasMessageId() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional int64 message_id = 4;</code>\n       */\n      public long getMessageId() {\n        return messageId_;\n      }\n      /**\n       * <code>optional int64 message_id = 4;</code>\n       */\n      public Builder setMessageId(long value) {\n        bitField0_ |= 0x00000008;\n        messageId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 message_id = 4;</code>\n       */\n      public Builder clearMessageId() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        messageId_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 server_timestamp = 5;\n      private long serverTimestamp_ ;\n      /**\n       * <code>optional int64 server_timestamp = 5;</code>\n       */\n      public boolean hasServerTimestamp() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional int64 server_timestamp = 5;</code>\n       */\n      public long getServerTimestamp() {\n        return serverTimestamp_;\n      }\n      /**\n       * <code>optional int64 server_timestamp = 5;</code>\n       */\n      public Builder setServerTimestamp(long value) {\n        bitField0_ |= 0x00000010;\n        serverTimestamp_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 server_timestamp = 5;</code>\n       */\n      public Builder clearServerTimestamp() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        serverTimestamp_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional string to_user = 6;\n      private java.lang.Object toUser_ = \"\";\n      /**\n       * <code>optional string to_user = 6;</code>\n       *\n       * <pre>\n       *not use anymore\n       * </pre>\n       */\n      public boolean hasToUser() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional string to_user = 6;</code>\n       *\n       * <pre>\n       *not use anymore\n       * </pre>\n       */\n      public java.lang.String getToUser() {\n        java.lang.Object ref = toUser_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          toUser_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string to_user = 6;</code>\n       *\n       * <pre>\n       *not use anymore\n       * </pre>\n       */\n      public com.google.protobuf.ByteString\n          getToUserBytes() {\n        java.lang.Object ref = toUser_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          toUser_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string to_user = 6;</code>\n       *\n       * <pre>\n       *not use anymore\n       * </pre>\n       */\n      public Builder setToUser(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        toUser_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string to_user = 6;</code>\n       *\n       * <pre>\n       *not use anymore\n       * </pre>\n       */\n      public Builder clearToUser() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        toUser_ = getDefaultInstance().getToUser();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string to_user = 6;</code>\n       *\n       * <pre>\n       *not use anymore\n       * </pre>\n       */\n      public Builder setToUserBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        toUser_ = value;\n        onChanged();\n        return this;\n      }\n\n      // repeated string to = 7;\n      private com.google.protobuf.LazyStringList to_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      private void ensureToIsMutable() {\n        if (!((bitField0_ & 0x00000040) == 0x00000040)) {\n          to_ = new com.google.protobuf.LazyStringArrayList(to_);\n          bitField0_ |= 0x00000040;\n         }\n      }\n      /**\n       * <code>repeated string to = 7;</code>\n       */\n      public java.util.List<java.lang.String>\n          getToList() {\n        return java.util.Collections.unmodifiableList(to_);\n      }\n      /**\n       * <code>repeated string to = 7;</code>\n       */\n      public int getToCount() {\n        return to_.size();\n      }\n      /**\n       * <code>repeated string to = 7;</code>\n       */\n      public java.lang.String getTo(int index) {\n        return to_.get(index);\n      }\n      /**\n       * <code>repeated string to = 7;</code>\n       */\n      public com.google.protobuf.ByteString\n          getToBytes(int index) {\n        return to_.getByteString(index);\n      }\n      /**\n       * <code>repeated string to = 7;</code>\n       */\n      public Builder setTo(\n          int index, java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureToIsMutable();\n        to_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string to = 7;</code>\n       */\n      public Builder addTo(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureToIsMutable();\n        to_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string to = 7;</code>\n       */\n      public Builder addAllTo(\n          java.lang.Iterable<java.lang.String> values) {\n        ensureToIsMutable();\n        super.addAll(values, to_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string to = 7;</code>\n       */\n      public Builder clearTo() {\n        to_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000040);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string to = 7;</code>\n       */\n      public Builder addToBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureToIsMutable();\n        to_.add(value);\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:Message)\n    }\n\n    static {\n      defaultInstance = new Message(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:Message)\n  }\n\n  public interface UserOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string uid = 1;\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    boolean hasUid();\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    java.lang.String getUid();\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getUidBytes();\n\n    // optional string name = 2;\n    /**\n     * <code>optional string name = 2;</code>\n     */\n    boolean hasName();\n    /**\n     * <code>optional string name = 2;</code>\n     */\n    java.lang.String getName();\n    /**\n     * <code>optional string name = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getNameBytes();\n\n    // optional string display_name = 3;\n    /**\n     * <code>optional string display_name = 3;</code>\n     */\n    boolean hasDisplayName();\n    /**\n     * <code>optional string display_name = 3;</code>\n     */\n    java.lang.String getDisplayName();\n    /**\n     * <code>optional string display_name = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getDisplayNameBytes();\n\n    // optional string portrait = 4;\n    /**\n     * <code>optional string portrait = 4;</code>\n     */\n    boolean hasPortrait();\n    /**\n     * <code>optional string portrait = 4;</code>\n     */\n    java.lang.String getPortrait();\n    /**\n     * <code>optional string portrait = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getPortraitBytes();\n\n    // optional string mobile = 5;\n    /**\n     * <code>optional string mobile = 5;</code>\n     */\n    boolean hasMobile();\n    /**\n     * <code>optional string mobile = 5;</code>\n     */\n    java.lang.String getMobile();\n    /**\n     * <code>optional string mobile = 5;</code>\n     */\n    com.google.protobuf.ByteString\n        getMobileBytes();\n\n    // optional string email = 6;\n    /**\n     * <code>optional string email = 6;</code>\n     */\n    boolean hasEmail();\n    /**\n     * <code>optional string email = 6;</code>\n     */\n    java.lang.String getEmail();\n    /**\n     * <code>optional string email = 6;</code>\n     */\n    com.google.protobuf.ByteString\n        getEmailBytes();\n\n    // optional string address = 7;\n    /**\n     * <code>optional string address = 7;</code>\n     */\n    boolean hasAddress();\n    /**\n     * <code>optional string address = 7;</code>\n     */\n    java.lang.String getAddress();\n    /**\n     * <code>optional string address = 7;</code>\n     */\n    com.google.protobuf.ByteString\n        getAddressBytes();\n\n    // optional string company = 8;\n    /**\n     * <code>optional string company = 8;</code>\n     */\n    boolean hasCompany();\n    /**\n     * <code>optional string company = 8;</code>\n     */\n    java.lang.String getCompany();\n    /**\n     * <code>optional string company = 8;</code>\n     */\n    com.google.protobuf.ByteString\n        getCompanyBytes();\n\n    // optional string extra = 9;\n    /**\n     * <code>optional string extra = 9;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 9;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 9;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n\n    // optional int64 update_dt = 10;\n    /**\n     * <code>optional int64 update_dt = 10;</code>\n     */\n    boolean hasUpdateDt();\n    /**\n     * <code>optional int64 update_dt = 10;</code>\n     */\n    long getUpdateDt();\n\n    // optional int32 gender = 11;\n    /**\n     * <code>optional int32 gender = 11;</code>\n     */\n    boolean hasGender();\n    /**\n     * <code>optional int32 gender = 11;</code>\n     */\n    int getGender();\n\n    // optional string social = 12;\n    /**\n     * <code>optional string social = 12;</code>\n     */\n    boolean hasSocial();\n    /**\n     * <code>optional string social = 12;</code>\n     */\n    java.lang.String getSocial();\n    /**\n     * <code>optional string social = 12;</code>\n     */\n    com.google.protobuf.ByteString\n        getSocialBytes();\n\n    // optional int32 type = 13;\n    /**\n     * <code>optional int32 type = 13;</code>\n     *\n     * <pre>\n     *0 normal user; 1 robot\n     * </pre>\n     */\n    boolean hasType();\n    /**\n     * <code>optional int32 type = 13;</code>\n     *\n     * <pre>\n     *0 normal user; 1 robot\n     * </pre>\n     */\n    int getType();\n\n    // optional int32 deleted = 14;\n    /**\n     * <code>optional int32 deleted = 14;</code>\n     */\n    boolean hasDeleted();\n    /**\n     * <code>optional int32 deleted = 14;</code>\n     */\n    int getDeleted();\n  }\n  /**\n   * Protobuf type {@code User}\n   */\n  public static final class User extends\n      com.google.protobuf.GeneratedMessage\n      implements UserOrBuilder {\n    // Use User.newBuilder() to construct.\n    private User(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private User(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final User defaultInstance;\n    public static User getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public User getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private User(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              uid_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              name_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              displayName_ = input.readBytes();\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000008;\n              portrait_ = input.readBytes();\n              break;\n            }\n            case 42: {\n              bitField0_ |= 0x00000010;\n              mobile_ = input.readBytes();\n              break;\n            }\n            case 50: {\n              bitField0_ |= 0x00000020;\n              email_ = input.readBytes();\n              break;\n            }\n            case 58: {\n              bitField0_ |= 0x00000040;\n              address_ = input.readBytes();\n              break;\n            }\n            case 66: {\n              bitField0_ |= 0x00000080;\n              company_ = input.readBytes();\n              break;\n            }\n            case 74: {\n              bitField0_ |= 0x00000100;\n              extra_ = input.readBytes();\n              break;\n            }\n            case 80: {\n              bitField0_ |= 0x00000200;\n              updateDt_ = input.readInt64();\n              break;\n            }\n            case 88: {\n              bitField0_ |= 0x00000400;\n              gender_ = input.readInt32();\n              break;\n            }\n            case 98: {\n              bitField0_ |= 0x00000800;\n              social_ = input.readBytes();\n              break;\n            }\n            case 104: {\n              bitField0_ |= 0x00001000;\n              type_ = input.readInt32();\n              break;\n            }\n            case 112: {\n              bitField0_ |= 0x00002000;\n              deleted_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_User_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_User_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.User.class, cn.wildfirechat.proto.WFCMessage.User.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<User> PARSER =\n        new com.google.protobuf.AbstractParser<User>() {\n      public User parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new User(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<User> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string uid = 1;\n    public static final int UID_FIELD_NUMBER = 1;\n    private java.lang.Object uid_;\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public boolean hasUid() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public java.lang.String getUid() {\n      java.lang.Object ref = uid_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          uid_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getUidBytes() {\n      java.lang.Object ref = uid_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        uid_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string name = 2;\n    public static final int NAME_FIELD_NUMBER = 2;\n    private java.lang.Object name_;\n    /**\n     * <code>optional string name = 2;</code>\n     */\n    public boolean hasName() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional string name = 2;</code>\n     */\n    public java.lang.String getName() {\n      java.lang.Object ref = name_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          name_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string name = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getNameBytes() {\n      java.lang.Object ref = name_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        name_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string display_name = 3;\n    public static final int DISPLAY_NAME_FIELD_NUMBER = 3;\n    private java.lang.Object displayName_;\n    /**\n     * <code>optional string display_name = 3;</code>\n     */\n    public boolean hasDisplayName() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string display_name = 3;</code>\n     */\n    public java.lang.String getDisplayName() {\n      java.lang.Object ref = displayName_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          displayName_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string display_name = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDisplayNameBytes() {\n      java.lang.Object ref = displayName_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        displayName_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string portrait = 4;\n    public static final int PORTRAIT_FIELD_NUMBER = 4;\n    private java.lang.Object portrait_;\n    /**\n     * <code>optional string portrait = 4;</code>\n     */\n    public boolean hasPortrait() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional string portrait = 4;</code>\n     */\n    public java.lang.String getPortrait() {\n      java.lang.Object ref = portrait_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          portrait_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string portrait = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getPortraitBytes() {\n      java.lang.Object ref = portrait_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        portrait_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string mobile = 5;\n    public static final int MOBILE_FIELD_NUMBER = 5;\n    private java.lang.Object mobile_;\n    /**\n     * <code>optional string mobile = 5;</code>\n     */\n    public boolean hasMobile() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional string mobile = 5;</code>\n     */\n    public java.lang.String getMobile() {\n      java.lang.Object ref = mobile_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          mobile_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string mobile = 5;</code>\n     */\n    public com.google.protobuf.ByteString\n        getMobileBytes() {\n      java.lang.Object ref = mobile_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        mobile_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string email = 6;\n    public static final int EMAIL_FIELD_NUMBER = 6;\n    private java.lang.Object email_;\n    /**\n     * <code>optional string email = 6;</code>\n     */\n    public boolean hasEmail() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional string email = 6;</code>\n     */\n    public java.lang.String getEmail() {\n      java.lang.Object ref = email_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          email_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string email = 6;</code>\n     */\n    public com.google.protobuf.ByteString\n        getEmailBytes() {\n      java.lang.Object ref = email_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        email_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string address = 7;\n    public static final int ADDRESS_FIELD_NUMBER = 7;\n    private java.lang.Object address_;\n    /**\n     * <code>optional string address = 7;</code>\n     */\n    public boolean hasAddress() {\n      return ((bitField0_ & 0x00000040) == 0x00000040);\n    }\n    /**\n     * <code>optional string address = 7;</code>\n     */\n    public java.lang.String getAddress() {\n      java.lang.Object ref = address_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          address_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string address = 7;</code>\n     */\n    public com.google.protobuf.ByteString\n        getAddressBytes() {\n      java.lang.Object ref = address_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        address_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string company = 8;\n    public static final int COMPANY_FIELD_NUMBER = 8;\n    private java.lang.Object company_;\n    /**\n     * <code>optional string company = 8;</code>\n     */\n    public boolean hasCompany() {\n      return ((bitField0_ & 0x00000080) == 0x00000080);\n    }\n    /**\n     * <code>optional string company = 8;</code>\n     */\n    public java.lang.String getCompany() {\n      java.lang.Object ref = company_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          company_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string company = 8;</code>\n     */\n    public com.google.protobuf.ByteString\n        getCompanyBytes() {\n      java.lang.Object ref = company_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        company_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string extra = 9;\n    public static final int EXTRA_FIELD_NUMBER = 9;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 9;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000100) == 0x00000100);\n    }\n    /**\n     * <code>optional string extra = 9;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 9;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int64 update_dt = 10;\n    public static final int UPDATE_DT_FIELD_NUMBER = 10;\n    private long updateDt_;\n    /**\n     * <code>optional int64 update_dt = 10;</code>\n     */\n    public boolean hasUpdateDt() {\n      return ((bitField0_ & 0x00000200) == 0x00000200);\n    }\n    /**\n     * <code>optional int64 update_dt = 10;</code>\n     */\n    public long getUpdateDt() {\n      return updateDt_;\n    }\n\n    // optional int32 gender = 11;\n    public static final int GENDER_FIELD_NUMBER = 11;\n    private int gender_;\n    /**\n     * <code>optional int32 gender = 11;</code>\n     */\n    public boolean hasGender() {\n      return ((bitField0_ & 0x00000400) == 0x00000400);\n    }\n    /**\n     * <code>optional int32 gender = 11;</code>\n     */\n    public int getGender() {\n      return gender_;\n    }\n\n    // optional string social = 12;\n    public static final int SOCIAL_FIELD_NUMBER = 12;\n    private java.lang.Object social_;\n    /**\n     * <code>optional string social = 12;</code>\n     */\n    public boolean hasSocial() {\n      return ((bitField0_ & 0x00000800) == 0x00000800);\n    }\n    /**\n     * <code>optional string social = 12;</code>\n     */\n    public java.lang.String getSocial() {\n      java.lang.Object ref = social_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          social_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string social = 12;</code>\n     */\n    public com.google.protobuf.ByteString\n        getSocialBytes() {\n      java.lang.Object ref = social_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        social_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 type = 13;\n    public static final int TYPE_FIELD_NUMBER = 13;\n    private int type_;\n    /**\n     * <code>optional int32 type = 13;</code>\n     *\n     * <pre>\n     *0 normal user; 1 robot\n     * </pre>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00001000) == 0x00001000);\n    }\n    /**\n     * <code>optional int32 type = 13;</code>\n     *\n     * <pre>\n     *0 normal user; 1 robot\n     * </pre>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    // optional int32 deleted = 14;\n    public static final int DELETED_FIELD_NUMBER = 14;\n    private int deleted_;\n    /**\n     * <code>optional int32 deleted = 14;</code>\n     */\n    public boolean hasDeleted() {\n      return ((bitField0_ & 0x00002000) == 0x00002000);\n    }\n    /**\n     * <code>optional int32 deleted = 14;</code>\n     */\n    public int getDeleted() {\n      return deleted_;\n    }\n\n    private void initFields() {\n      uid_ = \"\";\n      name_ = \"\";\n      displayName_ = \"\";\n      portrait_ = \"\";\n      mobile_ = \"\";\n      email_ = \"\";\n      address_ = \"\";\n      company_ = \"\";\n      extra_ = \"\";\n      updateDt_ = 0L;\n      gender_ = 0;\n      social_ = \"\";\n      type_ = 0;\n      deleted_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasUid()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getNameBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getDisplayNameBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(4, getPortraitBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeBytes(5, getMobileBytes());\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeBytes(6, getEmailBytes());\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        output.writeBytes(7, getAddressBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        output.writeBytes(8, getCompanyBytes());\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        output.writeBytes(9, getExtraBytes());\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        output.writeInt64(10, updateDt_);\n      }\n      if (((bitField0_ & 0x00000400) == 0x00000400)) {\n        output.writeInt32(11, gender_);\n      }\n      if (((bitField0_ & 0x00000800) == 0x00000800)) {\n        output.writeBytes(12, getSocialBytes());\n      }\n      if (((bitField0_ & 0x00001000) == 0x00001000)) {\n        output.writeInt32(13, type_);\n      }\n      if (((bitField0_ & 0x00002000) == 0x00002000)) {\n        output.writeInt32(14, deleted_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getNameBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getDisplayNameBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, getPortraitBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5, getMobileBytes());\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(6, getEmailBytes());\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(7, getAddressBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(8, getCompanyBytes());\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(9, getExtraBytes());\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(10, updateDt_);\n      }\n      if (((bitField0_ & 0x00000400) == 0x00000400)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(11, gender_);\n      }\n      if (((bitField0_ & 0x00000800) == 0x00000800)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(12, getSocialBytes());\n      }\n      if (((bitField0_ & 0x00001000) == 0x00001000)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(13, type_);\n      }\n      if (((bitField0_ & 0x00002000) == 0x00002000)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(14, deleted_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.User parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.User parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.User parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.User parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.User parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.User parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.User parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.User parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.User parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.User parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.User prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code User}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.UserOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_User_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_User_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.User.class, cn.wildfirechat.proto.WFCMessage.User.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.User.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        uid_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        name_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        displayName_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        portrait_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        mobile_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000010);\n        email_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000020);\n        address_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000040);\n        company_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000080);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000100);\n        updateDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000200);\n        gender_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000400);\n        social_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000800);\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00001000);\n        deleted_ = 0;\n        bitField0_ = (bitField0_ & ~0x00002000);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_User_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.User getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.User.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.User build() {\n        cn.wildfirechat.proto.WFCMessage.User result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.User buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.User result = new cn.wildfirechat.proto.WFCMessage.User(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.uid_ = uid_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.name_ = name_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.displayName_ = displayName_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.portrait_ = portrait_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.mobile_ = mobile_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.email_ = email_;\n        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {\n          to_bitField0_ |= 0x00000040;\n        }\n        result.address_ = address_;\n        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {\n          to_bitField0_ |= 0x00000080;\n        }\n        result.company_ = company_;\n        if (((from_bitField0_ & 0x00000100) == 0x00000100)) {\n          to_bitField0_ |= 0x00000100;\n        }\n        result.extra_ = extra_;\n        if (((from_bitField0_ & 0x00000200) == 0x00000200)) {\n          to_bitField0_ |= 0x00000200;\n        }\n        result.updateDt_ = updateDt_;\n        if (((from_bitField0_ & 0x00000400) == 0x00000400)) {\n          to_bitField0_ |= 0x00000400;\n        }\n        result.gender_ = gender_;\n        if (((from_bitField0_ & 0x00000800) == 0x00000800)) {\n          to_bitField0_ |= 0x00000800;\n        }\n        result.social_ = social_;\n        if (((from_bitField0_ & 0x00001000) == 0x00001000)) {\n          to_bitField0_ |= 0x00001000;\n        }\n        result.type_ = type_;\n        if (((from_bitField0_ & 0x00002000) == 0x00002000)) {\n          to_bitField0_ |= 0x00002000;\n        }\n        result.deleted_ = deleted_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.User) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.User)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.User other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.User.getDefaultInstance()) return this;\n        if (other.hasUid()) {\n          bitField0_ |= 0x00000001;\n          uid_ = other.uid_;\n          onChanged();\n        }\n        if (other.hasName()) {\n          bitField0_ |= 0x00000002;\n          name_ = other.name_;\n          onChanged();\n        }\n        if (other.hasDisplayName()) {\n          bitField0_ |= 0x00000004;\n          displayName_ = other.displayName_;\n          onChanged();\n        }\n        if (other.hasPortrait()) {\n          bitField0_ |= 0x00000008;\n          portrait_ = other.portrait_;\n          onChanged();\n        }\n        if (other.hasMobile()) {\n          bitField0_ |= 0x00000010;\n          mobile_ = other.mobile_;\n          onChanged();\n        }\n        if (other.hasEmail()) {\n          bitField0_ |= 0x00000020;\n          email_ = other.email_;\n          onChanged();\n        }\n        if (other.hasAddress()) {\n          bitField0_ |= 0x00000040;\n          address_ = other.address_;\n          onChanged();\n        }\n        if (other.hasCompany()) {\n          bitField0_ |= 0x00000080;\n          company_ = other.company_;\n          onChanged();\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000100;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        if (other.hasUpdateDt()) {\n          setUpdateDt(other.getUpdateDt());\n        }\n        if (other.hasGender()) {\n          setGender(other.getGender());\n        }\n        if (other.hasSocial()) {\n          bitField0_ |= 0x00000800;\n          social_ = other.social_;\n          onChanged();\n        }\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        if (other.hasDeleted()) {\n          setDeleted(other.getDeleted());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasUid()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.User parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.User) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string uid = 1;\n      private java.lang.Object uid_ = \"\";\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public boolean hasUid() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public java.lang.String getUid() {\n        java.lang.Object ref = uid_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          uid_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getUidBytes() {\n        java.lang.Object ref = uid_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          uid_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder setUid(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        uid_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder clearUid() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        uid_ = getDefaultInstance().getUid();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder setUidBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        uid_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string name = 2;\n      private java.lang.Object name_ = \"\";\n      /**\n       * <code>optional string name = 2;</code>\n       */\n      public boolean hasName() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional string name = 2;</code>\n       */\n      public java.lang.String getName() {\n        java.lang.Object ref = name_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          name_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string name = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getNameBytes() {\n        java.lang.Object ref = name_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          name_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string name = 2;</code>\n       */\n      public Builder setName(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        name_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string name = 2;</code>\n       */\n      public Builder clearName() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        name_ = getDefaultInstance().getName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string name = 2;</code>\n       */\n      public Builder setNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        name_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string display_name = 3;\n      private java.lang.Object displayName_ = \"\";\n      /**\n       * <code>optional string display_name = 3;</code>\n       */\n      public boolean hasDisplayName() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional string display_name = 3;</code>\n       */\n      public java.lang.String getDisplayName() {\n        java.lang.Object ref = displayName_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          displayName_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string display_name = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDisplayNameBytes() {\n        java.lang.Object ref = displayName_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          displayName_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string display_name = 3;</code>\n       */\n      public Builder setDisplayName(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        displayName_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string display_name = 3;</code>\n       */\n      public Builder clearDisplayName() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        displayName_ = getDefaultInstance().getDisplayName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string display_name = 3;</code>\n       */\n      public Builder setDisplayNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        displayName_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string portrait = 4;\n      private java.lang.Object portrait_ = \"\";\n      /**\n       * <code>optional string portrait = 4;</code>\n       */\n      public boolean hasPortrait() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional string portrait = 4;</code>\n       */\n      public java.lang.String getPortrait() {\n        java.lang.Object ref = portrait_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          portrait_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string portrait = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getPortraitBytes() {\n        java.lang.Object ref = portrait_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          portrait_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string portrait = 4;</code>\n       */\n      public Builder setPortrait(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        portrait_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string portrait = 4;</code>\n       */\n      public Builder clearPortrait() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        portrait_ = getDefaultInstance().getPortrait();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string portrait = 4;</code>\n       */\n      public Builder setPortraitBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        portrait_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string mobile = 5;\n      private java.lang.Object mobile_ = \"\";\n      /**\n       * <code>optional string mobile = 5;</code>\n       */\n      public boolean hasMobile() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional string mobile = 5;</code>\n       */\n      public java.lang.String getMobile() {\n        java.lang.Object ref = mobile_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          mobile_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string mobile = 5;</code>\n       */\n      public com.google.protobuf.ByteString\n          getMobileBytes() {\n        java.lang.Object ref = mobile_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          mobile_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string mobile = 5;</code>\n       */\n      public Builder setMobile(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        mobile_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string mobile = 5;</code>\n       */\n      public Builder clearMobile() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        mobile_ = getDefaultInstance().getMobile();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string mobile = 5;</code>\n       */\n      public Builder setMobileBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        mobile_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string email = 6;\n      private java.lang.Object email_ = \"\";\n      /**\n       * <code>optional string email = 6;</code>\n       */\n      public boolean hasEmail() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional string email = 6;</code>\n       */\n      public java.lang.String getEmail() {\n        java.lang.Object ref = email_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          email_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string email = 6;</code>\n       */\n      public com.google.protobuf.ByteString\n          getEmailBytes() {\n        java.lang.Object ref = email_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          email_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string email = 6;</code>\n       */\n      public Builder setEmail(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        email_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string email = 6;</code>\n       */\n      public Builder clearEmail() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        email_ = getDefaultInstance().getEmail();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string email = 6;</code>\n       */\n      public Builder setEmailBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        email_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string address = 7;\n      private java.lang.Object address_ = \"\";\n      /**\n       * <code>optional string address = 7;</code>\n       */\n      public boolean hasAddress() {\n        return ((bitField0_ & 0x00000040) == 0x00000040);\n      }\n      /**\n       * <code>optional string address = 7;</code>\n       */\n      public java.lang.String getAddress() {\n        java.lang.Object ref = address_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          address_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string address = 7;</code>\n       */\n      public com.google.protobuf.ByteString\n          getAddressBytes() {\n        java.lang.Object ref = address_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          address_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string address = 7;</code>\n       */\n      public Builder setAddress(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        address_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string address = 7;</code>\n       */\n      public Builder clearAddress() {\n        bitField0_ = (bitField0_ & ~0x00000040);\n        address_ = getDefaultInstance().getAddress();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string address = 7;</code>\n       */\n      public Builder setAddressBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        address_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string company = 8;\n      private java.lang.Object company_ = \"\";\n      /**\n       * <code>optional string company = 8;</code>\n       */\n      public boolean hasCompany() {\n        return ((bitField0_ & 0x00000080) == 0x00000080);\n      }\n      /**\n       * <code>optional string company = 8;</code>\n       */\n      public java.lang.String getCompany() {\n        java.lang.Object ref = company_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          company_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string company = 8;</code>\n       */\n      public com.google.protobuf.ByteString\n          getCompanyBytes() {\n        java.lang.Object ref = company_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          company_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string company = 8;</code>\n       */\n      public Builder setCompany(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000080;\n        company_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string company = 8;</code>\n       */\n      public Builder clearCompany() {\n        bitField0_ = (bitField0_ & ~0x00000080);\n        company_ = getDefaultInstance().getCompany();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string company = 8;</code>\n       */\n      public Builder setCompanyBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000080;\n        company_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string extra = 9;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 9;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000100) == 0x00000100);\n      }\n      /**\n       * <code>optional string extra = 9;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 9;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 9;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000100;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 9;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000100);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 9;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000100;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 update_dt = 10;\n      private long updateDt_ ;\n      /**\n       * <code>optional int64 update_dt = 10;</code>\n       */\n      public boolean hasUpdateDt() {\n        return ((bitField0_ & 0x00000200) == 0x00000200);\n      }\n      /**\n       * <code>optional int64 update_dt = 10;</code>\n       */\n      public long getUpdateDt() {\n        return updateDt_;\n      }\n      /**\n       * <code>optional int64 update_dt = 10;</code>\n       */\n      public Builder setUpdateDt(long value) {\n        bitField0_ |= 0x00000200;\n        updateDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 update_dt = 10;</code>\n       */\n      public Builder clearUpdateDt() {\n        bitField0_ = (bitField0_ & ~0x00000200);\n        updateDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 gender = 11;\n      private int gender_ ;\n      /**\n       * <code>optional int32 gender = 11;</code>\n       */\n      public boolean hasGender() {\n        return ((bitField0_ & 0x00000400) == 0x00000400);\n      }\n      /**\n       * <code>optional int32 gender = 11;</code>\n       */\n      public int getGender() {\n        return gender_;\n      }\n      /**\n       * <code>optional int32 gender = 11;</code>\n       */\n      public Builder setGender(int value) {\n        bitField0_ |= 0x00000400;\n        gender_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 gender = 11;</code>\n       */\n      public Builder clearGender() {\n        bitField0_ = (bitField0_ & ~0x00000400);\n        gender_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional string social = 12;\n      private java.lang.Object social_ = \"\";\n      /**\n       * <code>optional string social = 12;</code>\n       */\n      public boolean hasSocial() {\n        return ((bitField0_ & 0x00000800) == 0x00000800);\n      }\n      /**\n       * <code>optional string social = 12;</code>\n       */\n      public java.lang.String getSocial() {\n        java.lang.Object ref = social_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          social_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string social = 12;</code>\n       */\n      public com.google.protobuf.ByteString\n          getSocialBytes() {\n        java.lang.Object ref = social_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          social_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string social = 12;</code>\n       */\n      public Builder setSocial(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000800;\n        social_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string social = 12;</code>\n       */\n      public Builder clearSocial() {\n        bitField0_ = (bitField0_ & ~0x00000800);\n        social_ = getDefaultInstance().getSocial();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string social = 12;</code>\n       */\n      public Builder setSocialBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000800;\n        social_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 type = 13;\n      private int type_ ;\n      /**\n       * <code>optional int32 type = 13;</code>\n       *\n       * <pre>\n       *0 normal user; 1 robot\n       * </pre>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00001000) == 0x00001000);\n      }\n      /**\n       * <code>optional int32 type = 13;</code>\n       *\n       * <pre>\n       *0 normal user; 1 robot\n       * </pre>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>optional int32 type = 13;</code>\n       *\n       * <pre>\n       *0 normal user; 1 robot\n       * </pre>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00001000;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 type = 13;</code>\n       *\n       * <pre>\n       *0 normal user; 1 robot\n       * </pre>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00001000);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 deleted = 14;\n      private int deleted_ ;\n      /**\n       * <code>optional int32 deleted = 14;</code>\n       */\n      public boolean hasDeleted() {\n        return ((bitField0_ & 0x00002000) == 0x00002000);\n      }\n      /**\n       * <code>optional int32 deleted = 14;</code>\n       */\n      public int getDeleted() {\n        return deleted_;\n      }\n      /**\n       * <code>optional int32 deleted = 14;</code>\n       */\n      public Builder setDeleted(int value) {\n        bitField0_ |= 0x00002000;\n        deleted_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 deleted = 14;</code>\n       */\n      public Builder clearDeleted() {\n        bitField0_ = (bitField0_ & ~0x00002000);\n        deleted_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:User)\n    }\n\n    static {\n      defaultInstance = new User(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:User)\n  }\n\n  public interface RobotOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string uid = 1;\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    boolean hasUid();\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    java.lang.String getUid();\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getUidBytes();\n\n    // required int32 state = 2;\n    /**\n     * <code>required int32 state = 2;</code>\n     *\n     * <pre>\n     *0 normal; 1 deleted;\n     * </pre>\n     */\n    boolean hasState();\n    /**\n     * <code>required int32 state = 2;</code>\n     *\n     * <pre>\n     *0 normal; 1 deleted;\n     * </pre>\n     */\n    int getState();\n\n    // optional string owner = 3;\n    /**\n     * <code>optional string owner = 3;</code>\n     */\n    boolean hasOwner();\n    /**\n     * <code>optional string owner = 3;</code>\n     */\n    java.lang.String getOwner();\n    /**\n     * <code>optional string owner = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getOwnerBytes();\n\n    // optional string secret = 4;\n    /**\n     * <code>optional string secret = 4;</code>\n     */\n    boolean hasSecret();\n    /**\n     * <code>optional string secret = 4;</code>\n     */\n    java.lang.String getSecret();\n    /**\n     * <code>optional string secret = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getSecretBytes();\n\n    // optional string callback = 5;\n    /**\n     * <code>optional string callback = 5;</code>\n     */\n    boolean hasCallback();\n    /**\n     * <code>optional string callback = 5;</code>\n     */\n    java.lang.String getCallback();\n    /**\n     * <code>optional string callback = 5;</code>\n     */\n    com.google.protobuf.ByteString\n        getCallbackBytes();\n\n    // optional string extra = 6;\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n  }\n  /**\n   * Protobuf type {@code Robot}\n   */\n  public static final class Robot extends\n      com.google.protobuf.GeneratedMessage\n      implements RobotOrBuilder {\n    // Use Robot.newBuilder() to construct.\n    private Robot(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private Robot(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final Robot defaultInstance;\n    public static Robot getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public Robot getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Robot(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              uid_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              state_ = input.readInt32();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              owner_ = input.readBytes();\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000008;\n              secret_ = input.readBytes();\n              break;\n            }\n            case 42: {\n              bitField0_ |= 0x00000010;\n              callback_ = input.readBytes();\n              break;\n            }\n            case 50: {\n              bitField0_ |= 0x00000020;\n              extra_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_Robot_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_Robot_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.Robot.class, cn.wildfirechat.proto.WFCMessage.Robot.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<Robot> PARSER =\n        new com.google.protobuf.AbstractParser<Robot>() {\n      public Robot parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Robot(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Robot> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string uid = 1;\n    public static final int UID_FIELD_NUMBER = 1;\n    private java.lang.Object uid_;\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public boolean hasUid() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public java.lang.String getUid() {\n      java.lang.Object ref = uid_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          uid_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getUidBytes() {\n      java.lang.Object ref = uid_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        uid_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 state = 2;\n    public static final int STATE_FIELD_NUMBER = 2;\n    private int state_;\n    /**\n     * <code>required int32 state = 2;</code>\n     *\n     * <pre>\n     *0 normal; 1 deleted;\n     * </pre>\n     */\n    public boolean hasState() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 state = 2;</code>\n     *\n     * <pre>\n     *0 normal; 1 deleted;\n     * </pre>\n     */\n    public int getState() {\n      return state_;\n    }\n\n    // optional string owner = 3;\n    public static final int OWNER_FIELD_NUMBER = 3;\n    private java.lang.Object owner_;\n    /**\n     * <code>optional string owner = 3;</code>\n     */\n    public boolean hasOwner() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string owner = 3;</code>\n     */\n    public java.lang.String getOwner() {\n      java.lang.Object ref = owner_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          owner_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string owner = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getOwnerBytes() {\n      java.lang.Object ref = owner_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        owner_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string secret = 4;\n    public static final int SECRET_FIELD_NUMBER = 4;\n    private java.lang.Object secret_;\n    /**\n     * <code>optional string secret = 4;</code>\n     */\n    public boolean hasSecret() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional string secret = 4;</code>\n     */\n    public java.lang.String getSecret() {\n      java.lang.Object ref = secret_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          secret_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string secret = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getSecretBytes() {\n      java.lang.Object ref = secret_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        secret_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string callback = 5;\n    public static final int CALLBACK_FIELD_NUMBER = 5;\n    private java.lang.Object callback_;\n    /**\n     * <code>optional string callback = 5;</code>\n     */\n    public boolean hasCallback() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional string callback = 5;</code>\n     */\n    public java.lang.String getCallback() {\n      java.lang.Object ref = callback_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          callback_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string callback = 5;</code>\n     */\n    public com.google.protobuf.ByteString\n        getCallbackBytes() {\n      java.lang.Object ref = callback_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        callback_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string extra = 6;\n    public static final int EXTRA_FIELD_NUMBER = 6;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      uid_ = \"\";\n      state_ = 0;\n      owner_ = \"\";\n      secret_ = \"\";\n      callback_ = \"\";\n      extra_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasUid()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasState()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, state_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getOwnerBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(4, getSecretBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeBytes(5, getCallbackBytes());\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeBytes(6, getExtraBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, state_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getOwnerBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, getSecretBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5, getCallbackBytes());\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(6, getExtraBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.Robot parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Robot parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Robot parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Robot parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Robot parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Robot parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Robot parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Robot parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Robot parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Robot parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.Robot prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code Robot}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.RobotOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Robot_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Robot_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.Robot.class, cn.wildfirechat.proto.WFCMessage.Robot.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.Robot.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        uid_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        state_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        owner_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        secret_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        callback_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000010);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000020);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Robot_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Robot getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.Robot.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Robot build() {\n        cn.wildfirechat.proto.WFCMessage.Robot result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Robot buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.Robot result = new cn.wildfirechat.proto.WFCMessage.Robot(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.uid_ = uid_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.state_ = state_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.owner_ = owner_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.secret_ = secret_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.callback_ = callback_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.extra_ = extra_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.Robot) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.Robot)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.Robot other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.Robot.getDefaultInstance()) return this;\n        if (other.hasUid()) {\n          bitField0_ |= 0x00000001;\n          uid_ = other.uid_;\n          onChanged();\n        }\n        if (other.hasState()) {\n          setState(other.getState());\n        }\n        if (other.hasOwner()) {\n          bitField0_ |= 0x00000004;\n          owner_ = other.owner_;\n          onChanged();\n        }\n        if (other.hasSecret()) {\n          bitField0_ |= 0x00000008;\n          secret_ = other.secret_;\n          onChanged();\n        }\n        if (other.hasCallback()) {\n          bitField0_ |= 0x00000010;\n          callback_ = other.callback_;\n          onChanged();\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000020;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasUid()) {\n          \n          return false;\n        }\n        if (!hasState()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.Robot parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.Robot) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string uid = 1;\n      private java.lang.Object uid_ = \"\";\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public boolean hasUid() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public java.lang.String getUid() {\n        java.lang.Object ref = uid_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          uid_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getUidBytes() {\n        java.lang.Object ref = uid_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          uid_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder setUid(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        uid_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder clearUid() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        uid_ = getDefaultInstance().getUid();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder setUidBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        uid_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 state = 2;\n      private int state_ ;\n      /**\n       * <code>required int32 state = 2;</code>\n       *\n       * <pre>\n       *0 normal; 1 deleted;\n       * </pre>\n       */\n      public boolean hasState() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 state = 2;</code>\n       *\n       * <pre>\n       *0 normal; 1 deleted;\n       * </pre>\n       */\n      public int getState() {\n        return state_;\n      }\n      /**\n       * <code>required int32 state = 2;</code>\n       *\n       * <pre>\n       *0 normal; 1 deleted;\n       * </pre>\n       */\n      public Builder setState(int value) {\n        bitField0_ |= 0x00000002;\n        state_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 state = 2;</code>\n       *\n       * <pre>\n       *0 normal; 1 deleted;\n       * </pre>\n       */\n      public Builder clearState() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        state_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional string owner = 3;\n      private java.lang.Object owner_ = \"\";\n      /**\n       * <code>optional string owner = 3;</code>\n       */\n      public boolean hasOwner() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional string owner = 3;</code>\n       */\n      public java.lang.String getOwner() {\n        java.lang.Object ref = owner_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          owner_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string owner = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getOwnerBytes() {\n        java.lang.Object ref = owner_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          owner_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string owner = 3;</code>\n       */\n      public Builder setOwner(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        owner_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string owner = 3;</code>\n       */\n      public Builder clearOwner() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        owner_ = getDefaultInstance().getOwner();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string owner = 3;</code>\n       */\n      public Builder setOwnerBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        owner_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string secret = 4;\n      private java.lang.Object secret_ = \"\";\n      /**\n       * <code>optional string secret = 4;</code>\n       */\n      public boolean hasSecret() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional string secret = 4;</code>\n       */\n      public java.lang.String getSecret() {\n        java.lang.Object ref = secret_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          secret_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string secret = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getSecretBytes() {\n        java.lang.Object ref = secret_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          secret_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string secret = 4;</code>\n       */\n      public Builder setSecret(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        secret_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string secret = 4;</code>\n       */\n      public Builder clearSecret() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        secret_ = getDefaultInstance().getSecret();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string secret = 4;</code>\n       */\n      public Builder setSecretBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        secret_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string callback = 5;\n      private java.lang.Object callback_ = \"\";\n      /**\n       * <code>optional string callback = 5;</code>\n       */\n      public boolean hasCallback() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional string callback = 5;</code>\n       */\n      public java.lang.String getCallback() {\n        java.lang.Object ref = callback_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          callback_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string callback = 5;</code>\n       */\n      public com.google.protobuf.ByteString\n          getCallbackBytes() {\n        java.lang.Object ref = callback_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          callback_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string callback = 5;</code>\n       */\n      public Builder setCallback(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        callback_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string callback = 5;</code>\n       */\n      public Builder clearCallback() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        callback_ = getDefaultInstance().getCallback();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string callback = 5;</code>\n       */\n      public Builder setCallbackBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        callback_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string extra = 6;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:Robot)\n    }\n\n    static {\n      defaultInstance = new Robot(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:Robot)\n  }\n\n  public interface GetRobotsResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .Robot entry = 1;\n    /**\n     * <code>repeated .Robot entry = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.Robot> \n        getEntryList();\n    /**\n     * <code>repeated .Robot entry = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.Robot getEntry(int index);\n    /**\n     * <code>repeated .Robot entry = 1;</code>\n     */\n    int getEntryCount();\n    /**\n     * <code>repeated .Robot entry = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.RobotOrBuilder> \n        getEntryOrBuilderList();\n    /**\n     * <code>repeated .Robot entry = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.RobotOrBuilder getEntryOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code GetRobotsResult}\n   */\n  public static final class GetRobotsResult extends\n      com.google.protobuf.GeneratedMessage\n      implements GetRobotsResultOrBuilder {\n    // Use GetRobotsResult.newBuilder() to construct.\n    private GetRobotsResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private GetRobotsResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final GetRobotsResult defaultInstance;\n    public static GetRobotsResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public GetRobotsResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private GetRobotsResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                entry_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.Robot>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              entry_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.Robot.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          entry_ = java.util.Collections.unmodifiableList(entry_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetRobotsResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetRobotsResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.GetRobotsResult.class, cn.wildfirechat.proto.WFCMessage.GetRobotsResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<GetRobotsResult> PARSER =\n        new com.google.protobuf.AbstractParser<GetRobotsResult>() {\n      public GetRobotsResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new GetRobotsResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<GetRobotsResult> getParserForType() {\n      return PARSER;\n    }\n\n    // repeated .Robot entry = 1;\n    public static final int ENTRY_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.Robot> entry_;\n    /**\n     * <code>repeated .Robot entry = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.Robot> getEntryList() {\n      return entry_;\n    }\n    /**\n     * <code>repeated .Robot entry = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.RobotOrBuilder> \n        getEntryOrBuilderList() {\n      return entry_;\n    }\n    /**\n     * <code>repeated .Robot entry = 1;</code>\n     */\n    public int getEntryCount() {\n      return entry_.size();\n    }\n    /**\n     * <code>repeated .Robot entry = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.Robot getEntry(int index) {\n      return entry_.get(index);\n    }\n    /**\n     * <code>repeated .Robot entry = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.RobotOrBuilder getEntryOrBuilder(\n        int index) {\n      return entry_.get(index);\n    }\n\n    private void initFields() {\n      entry_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      for (int i = 0; i < getEntryCount(); i++) {\n        if (!getEntry(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < entry_.size(); i++) {\n        output.writeMessage(1, entry_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < entry_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, entry_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.GetRobotsResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetRobotsResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetRobotsResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetRobotsResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetRobotsResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetRobotsResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetRobotsResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetRobotsResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetRobotsResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetRobotsResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.GetRobotsResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code GetRobotsResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GetRobotsResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetRobotsResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetRobotsResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.GetRobotsResult.class, cn.wildfirechat.proto.WFCMessage.GetRobotsResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.GetRobotsResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getEntryFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (entryBuilder_ == null) {\n          entry_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          entryBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetRobotsResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetRobotsResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.GetRobotsResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetRobotsResult build() {\n        cn.wildfirechat.proto.WFCMessage.GetRobotsResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetRobotsResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.GetRobotsResult result = new cn.wildfirechat.proto.WFCMessage.GetRobotsResult(this);\n        int from_bitField0_ = bitField0_;\n        if (entryBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            entry_ = java.util.Collections.unmodifiableList(entry_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.entry_ = entry_;\n        } else {\n          result.entry_ = entryBuilder_.build();\n        }\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.GetRobotsResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.GetRobotsResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.GetRobotsResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.GetRobotsResult.getDefaultInstance()) return this;\n        if (entryBuilder_ == null) {\n          if (!other.entry_.isEmpty()) {\n            if (entry_.isEmpty()) {\n              entry_ = other.entry_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureEntryIsMutable();\n              entry_.addAll(other.entry_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.entry_.isEmpty()) {\n            if (entryBuilder_.isEmpty()) {\n              entryBuilder_.dispose();\n              entryBuilder_ = null;\n              entry_ = other.entry_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              entryBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getEntryFieldBuilder() : null;\n            } else {\n              entryBuilder_.addAllMessages(other.entry_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        for (int i = 0; i < getEntryCount(); i++) {\n          if (!getEntry(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.GetRobotsResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.GetRobotsResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .Robot entry = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.Robot> entry_ =\n        java.util.Collections.emptyList();\n      private void ensureEntryIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          entry_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.Robot>(entry_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.Robot, cn.wildfirechat.proto.WFCMessage.Robot.Builder, cn.wildfirechat.proto.WFCMessage.RobotOrBuilder> entryBuilder_;\n\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.Robot> getEntryList() {\n        if (entryBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(entry_);\n        } else {\n          return entryBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public int getEntryCount() {\n        if (entryBuilder_ == null) {\n          return entry_.size();\n        } else {\n          return entryBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Robot getEntry(int index) {\n        if (entryBuilder_ == null) {\n          return entry_.get(index);\n        } else {\n          return entryBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public Builder setEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.Robot value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.set(index, value);\n          onChanged();\n        } else {\n          entryBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public Builder setEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.Robot.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public Builder addEntry(cn.wildfirechat.proto.WFCMessage.Robot value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.add(value);\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public Builder addEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.Robot value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.add(index, value);\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public Builder addEntry(\n          cn.wildfirechat.proto.WFCMessage.Robot.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.add(builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public Builder addEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.Robot.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public Builder addAllEntry(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.Robot> values) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          super.addAll(values, entry_);\n          onChanged();\n        } else {\n          entryBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public Builder clearEntry() {\n        if (entryBuilder_ == null) {\n          entry_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          entryBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public Builder removeEntry(int index) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.remove(index);\n          onChanged();\n        } else {\n          entryBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Robot.Builder getEntryBuilder(\n          int index) {\n        return getEntryFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.RobotOrBuilder getEntryOrBuilder(\n          int index) {\n        if (entryBuilder_ == null) {\n          return entry_.get(index);  } else {\n          return entryBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.RobotOrBuilder> \n           getEntryOrBuilderList() {\n        if (entryBuilder_ != null) {\n          return entryBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(entry_);\n        }\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Robot.Builder addEntryBuilder() {\n        return getEntryFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.Robot.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Robot.Builder addEntryBuilder(\n          int index) {\n        return getEntryFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.Robot.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .Robot entry = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.Robot.Builder> \n           getEntryBuilderList() {\n        return getEntryFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.Robot, cn.wildfirechat.proto.WFCMessage.Robot.Builder, cn.wildfirechat.proto.WFCMessage.RobotOrBuilder> \n          getEntryFieldBuilder() {\n        if (entryBuilder_ == null) {\n          entryBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.Robot, cn.wildfirechat.proto.WFCMessage.Robot.Builder, cn.wildfirechat.proto.WFCMessage.RobotOrBuilder>(\n                  entry_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          entry_ = null;\n        }\n        return entryBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:GetRobotsResult)\n    }\n\n    static {\n      defaultInstance = new GetRobotsResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:GetRobotsResult)\n  }\n\n  public interface UploadDeviceTokenRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int32 platform = 1;\n    /**\n     * <code>required int32 platform = 1;</code>\n     */\n    boolean hasPlatform();\n    /**\n     * <code>required int32 platform = 1;</code>\n     */\n    int getPlatform();\n\n    // required string app_name = 2;\n    /**\n     * <code>required string app_name = 2;</code>\n     */\n    boolean hasAppName();\n    /**\n     * <code>required string app_name = 2;</code>\n     */\n    java.lang.String getAppName();\n    /**\n     * <code>required string app_name = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getAppNameBytes();\n\n    // required string device_token = 3;\n    /**\n     * <code>required string device_token = 3;</code>\n     */\n    boolean hasDeviceToken();\n    /**\n     * <code>required string device_token = 3;</code>\n     */\n    java.lang.String getDeviceToken();\n    /**\n     * <code>required string device_token = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getDeviceTokenBytes();\n\n    // required int32 push_type = 4;\n    /**\n     * <code>required int32 push_type = 4;</code>\n     */\n    boolean hasPushType();\n    /**\n     * <code>required int32 push_type = 4;</code>\n     */\n    int getPushType();\n  }\n  /**\n   * Protobuf type {@code UploadDeviceTokenRequest}\n   */\n  public static final class UploadDeviceTokenRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements UploadDeviceTokenRequestOrBuilder {\n    // Use UploadDeviceTokenRequest.newBuilder() to construct.\n    private UploadDeviceTokenRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private UploadDeviceTokenRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final UploadDeviceTokenRequest defaultInstance;\n    public static UploadDeviceTokenRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public UploadDeviceTokenRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private UploadDeviceTokenRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              platform_ = input.readInt32();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              appName_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              deviceToken_ = input.readBytes();\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000008;\n              pushType_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_UploadDeviceTokenRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_UploadDeviceTokenRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest.class, cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<UploadDeviceTokenRequest> PARSER =\n        new com.google.protobuf.AbstractParser<UploadDeviceTokenRequest>() {\n      public UploadDeviceTokenRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new UploadDeviceTokenRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<UploadDeviceTokenRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int32 platform = 1;\n    public static final int PLATFORM_FIELD_NUMBER = 1;\n    private int platform_;\n    /**\n     * <code>required int32 platform = 1;</code>\n     */\n    public boolean hasPlatform() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int32 platform = 1;</code>\n     */\n    public int getPlatform() {\n      return platform_;\n    }\n\n    // required string app_name = 2;\n    public static final int APP_NAME_FIELD_NUMBER = 2;\n    private java.lang.Object appName_;\n    /**\n     * <code>required string app_name = 2;</code>\n     */\n    public boolean hasAppName() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string app_name = 2;</code>\n     */\n    public java.lang.String getAppName() {\n      java.lang.Object ref = appName_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          appName_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string app_name = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getAppNameBytes() {\n      java.lang.Object ref = appName_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        appName_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string device_token = 3;\n    public static final int DEVICE_TOKEN_FIELD_NUMBER = 3;\n    private java.lang.Object deviceToken_;\n    /**\n     * <code>required string device_token = 3;</code>\n     */\n    public boolean hasDeviceToken() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required string device_token = 3;</code>\n     */\n    public java.lang.String getDeviceToken() {\n      java.lang.Object ref = deviceToken_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          deviceToken_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string device_token = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDeviceTokenBytes() {\n      java.lang.Object ref = deviceToken_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        deviceToken_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 push_type = 4;\n    public static final int PUSH_TYPE_FIELD_NUMBER = 4;\n    private int pushType_;\n    /**\n     * <code>required int32 push_type = 4;</code>\n     */\n    public boolean hasPushType() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>required int32 push_type = 4;</code>\n     */\n    public int getPushType() {\n      return pushType_;\n    }\n\n    private void initFields() {\n      platform_ = 0;\n      appName_ = \"\";\n      deviceToken_ = \"\";\n      pushType_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasPlatform()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasAppName()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasDeviceToken()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasPushType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, platform_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getAppNameBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getDeviceTokenBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeInt32(4, pushType_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, platform_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getAppNameBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getDeviceTokenBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(4, pushType_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code UploadDeviceTokenRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_UploadDeviceTokenRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_UploadDeviceTokenRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest.class, cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        platform_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        appName_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        deviceToken_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        pushType_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_UploadDeviceTokenRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest build() {\n        cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest result = new cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.platform_ = platform_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.appName_ = appName_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.deviceToken_ = deviceToken_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.pushType_ = pushType_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest.getDefaultInstance()) return this;\n        if (other.hasPlatform()) {\n          setPlatform(other.getPlatform());\n        }\n        if (other.hasAppName()) {\n          bitField0_ |= 0x00000002;\n          appName_ = other.appName_;\n          onChanged();\n        }\n        if (other.hasDeviceToken()) {\n          bitField0_ |= 0x00000004;\n          deviceToken_ = other.deviceToken_;\n          onChanged();\n        }\n        if (other.hasPushType()) {\n          setPushType(other.getPushType());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasPlatform()) {\n          \n          return false;\n        }\n        if (!hasAppName()) {\n          \n          return false;\n        }\n        if (!hasDeviceToken()) {\n          \n          return false;\n        }\n        if (!hasPushType()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.UploadDeviceTokenRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int32 platform = 1;\n      private int platform_ ;\n      /**\n       * <code>required int32 platform = 1;</code>\n       */\n      public boolean hasPlatform() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int32 platform = 1;</code>\n       */\n      public int getPlatform() {\n        return platform_;\n      }\n      /**\n       * <code>required int32 platform = 1;</code>\n       */\n      public Builder setPlatform(int value) {\n        bitField0_ |= 0x00000001;\n        platform_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 platform = 1;</code>\n       */\n      public Builder clearPlatform() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        platform_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required string app_name = 2;\n      private java.lang.Object appName_ = \"\";\n      /**\n       * <code>required string app_name = 2;</code>\n       */\n      public boolean hasAppName() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string app_name = 2;</code>\n       */\n      public java.lang.String getAppName() {\n        java.lang.Object ref = appName_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          appName_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string app_name = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getAppNameBytes() {\n        java.lang.Object ref = appName_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          appName_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string app_name = 2;</code>\n       */\n      public Builder setAppName(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        appName_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string app_name = 2;</code>\n       */\n      public Builder clearAppName() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        appName_ = getDefaultInstance().getAppName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string app_name = 2;</code>\n       */\n      public Builder setAppNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        appName_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string device_token = 3;\n      private java.lang.Object deviceToken_ = \"\";\n      /**\n       * <code>required string device_token = 3;</code>\n       */\n      public boolean hasDeviceToken() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required string device_token = 3;</code>\n       */\n      public java.lang.String getDeviceToken() {\n        java.lang.Object ref = deviceToken_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          deviceToken_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string device_token = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDeviceTokenBytes() {\n        java.lang.Object ref = deviceToken_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          deviceToken_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string device_token = 3;</code>\n       */\n      public Builder setDeviceToken(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        deviceToken_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string device_token = 3;</code>\n       */\n      public Builder clearDeviceToken() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        deviceToken_ = getDefaultInstance().getDeviceToken();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string device_token = 3;</code>\n       */\n      public Builder setDeviceTokenBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        deviceToken_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 push_type = 4;\n      private int pushType_ ;\n      /**\n       * <code>required int32 push_type = 4;</code>\n       */\n      public boolean hasPushType() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>required int32 push_type = 4;</code>\n       */\n      public int getPushType() {\n        return pushType_;\n      }\n      /**\n       * <code>required int32 push_type = 4;</code>\n       */\n      public Builder setPushType(int value) {\n        bitField0_ |= 0x00000008;\n        pushType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 push_type = 4;</code>\n       */\n      public Builder clearPushType() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        pushType_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:UploadDeviceTokenRequest)\n    }\n\n    static {\n      defaultInstance = new UploadDeviceTokenRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:UploadDeviceTokenRequest)\n  }\n\n  public interface ModifyGroupInfoRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string group_id = 1;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    boolean hasGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    java.lang.String getGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getGroupIdBytes();\n\n    // required int32 type = 2;\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    int getType();\n\n    // required string value = 3;\n    /**\n     * <code>required string value = 3;</code>\n     */\n    boolean hasValue();\n    /**\n     * <code>required string value = 3;</code>\n     */\n    java.lang.String getValue();\n    /**\n     * <code>required string value = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getValueBytes();\n\n    // repeated int32 to_line = 4;\n    /**\n     * <code>repeated int32 to_line = 4;</code>\n     */\n    java.util.List<java.lang.Integer> getToLineList();\n    /**\n     * <code>repeated int32 to_line = 4;</code>\n     */\n    int getToLineCount();\n    /**\n     * <code>repeated int32 to_line = 4;</code>\n     */\n    int getToLine(int index);\n\n    // optional .MessageContent notify_content = 5;\n    /**\n     * <code>optional .MessageContent notify_content = 5;</code>\n     */\n    boolean hasNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 5;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 5;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder();\n  }\n  /**\n   * Protobuf type {@code ModifyGroupInfoRequest}\n   */\n  public static final class ModifyGroupInfoRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements ModifyGroupInfoRequestOrBuilder {\n    // Use ModifyGroupInfoRequest.newBuilder() to construct.\n    private ModifyGroupInfoRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ModifyGroupInfoRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ModifyGroupInfoRequest defaultInstance;\n    public static ModifyGroupInfoRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ModifyGroupInfoRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ModifyGroupInfoRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              groupId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              type_ = input.readInt32();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              value_ = input.readBytes();\n              break;\n            }\n            case 32: {\n              if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000008;\n              }\n              toLine_.add(input.readInt32());\n              break;\n            }\n            case 34: {\n              int length = input.readRawVarint32();\n              int limit = input.pushLimit(length);\n              if (!((mutable_bitField0_ & 0x00000008) == 0x00000008) && input.getBytesUntilLimit() > 0) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000008;\n              }\n              while (input.getBytesUntilLimit() > 0) {\n                toLine_.add(input.readInt32());\n              }\n              input.popLimit(limit);\n              break;\n            }\n            case 42: {\n              cn.wildfirechat.proto.WFCMessage.MessageContent.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000008) == 0x00000008)) {\n                subBuilder = notifyContent_.toBuilder();\n              }\n              notifyContent_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.MessageContent.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(notifyContent_);\n                notifyContent_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000008;\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupInfoRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupInfoRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest.class, cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ModifyGroupInfoRequest> PARSER =\n        new com.google.protobuf.AbstractParser<ModifyGroupInfoRequest>() {\n      public ModifyGroupInfoRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ModifyGroupInfoRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ModifyGroupInfoRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string group_id = 1;\n    public static final int GROUP_ID_FIELD_NUMBER = 1;\n    private java.lang.Object groupId_;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public boolean hasGroupId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public java.lang.String getGroupId() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          groupId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getGroupIdBytes() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        groupId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 type = 2;\n    public static final int TYPE_FIELD_NUMBER = 2;\n    private int type_;\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    // required string value = 3;\n    public static final int VALUE_FIELD_NUMBER = 3;\n    private java.lang.Object value_;\n    /**\n     * <code>required string value = 3;</code>\n     */\n    public boolean hasValue() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required string value = 3;</code>\n     */\n    public java.lang.String getValue() {\n      java.lang.Object ref = value_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          value_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string value = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getValueBytes() {\n      java.lang.Object ref = value_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        value_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // repeated int32 to_line = 4;\n    public static final int TO_LINE_FIELD_NUMBER = 4;\n    private java.util.List<java.lang.Integer> toLine_;\n    /**\n     * <code>repeated int32 to_line = 4;</code>\n     */\n    public java.util.List<java.lang.Integer>\n        getToLineList() {\n      return toLine_;\n    }\n    /**\n     * <code>repeated int32 to_line = 4;</code>\n     */\n    public int getToLineCount() {\n      return toLine_.size();\n    }\n    /**\n     * <code>repeated int32 to_line = 4;</code>\n     */\n    public int getToLine(int index) {\n      return toLine_.get(index);\n    }\n\n    // optional .MessageContent notify_content = 5;\n    public static final int NOTIFY_CONTENT_FIELD_NUMBER = 5;\n    private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_;\n    /**\n     * <code>optional .MessageContent notify_content = 5;</code>\n     */\n    public boolean hasNotifyContent() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 5;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n      return notifyContent_;\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 5;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n      return notifyContent_;\n    }\n\n    private void initFields() {\n      groupId_ = \"\";\n      type_ = 0;\n      value_ = \"\";\n      toLine_ = java.util.Collections.emptyList();\n      notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasGroupId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasValue()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (hasNotifyContent()) {\n        if (!getNotifyContent().isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getGroupIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, type_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getValueBytes());\n      }\n      for (int i = 0; i < toLine_.size(); i++) {\n        output.writeInt32(4, toLine_.get(i));\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeMessage(5, notifyContent_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getGroupIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, type_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getValueBytes());\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < toLine_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeInt32SizeNoTag(toLine_.get(i));\n        }\n        size += dataSize;\n        size += 1 * getToLineList().size();\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(5, notifyContent_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ModifyGroupInfoRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupInfoRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupInfoRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest.class, cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getNotifyContentFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        groupId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        value_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000008);\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000010);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupInfoRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest build() {\n        cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest result = new cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.groupId_ = groupId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.type_ = type_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.value_ = value_;\n        if (((bitField0_ & 0x00000008) == 0x00000008)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n          bitField0_ = (bitField0_ & ~0x00000008);\n        }\n        result.toLine_ = toLine_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        if (notifyContentBuilder_ == null) {\n          result.notifyContent_ = notifyContent_;\n        } else {\n          result.notifyContent_ = notifyContentBuilder_.build();\n        }\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest.getDefaultInstance()) return this;\n        if (other.hasGroupId()) {\n          bitField0_ |= 0x00000001;\n          groupId_ = other.groupId_;\n          onChanged();\n        }\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        if (other.hasValue()) {\n          bitField0_ |= 0x00000004;\n          value_ = other.value_;\n          onChanged();\n        }\n        if (!other.toLine_.isEmpty()) {\n          if (toLine_.isEmpty()) {\n            toLine_ = other.toLine_;\n            bitField0_ = (bitField0_ & ~0x00000008);\n          } else {\n            ensureToLineIsMutable();\n            toLine_.addAll(other.toLine_);\n          }\n          onChanged();\n        }\n        if (other.hasNotifyContent()) {\n          mergeNotifyContent(other.getNotifyContent());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasGroupId()) {\n          \n          return false;\n        }\n        if (!hasType()) {\n          \n          return false;\n        }\n        if (!hasValue()) {\n          \n          return false;\n        }\n        if (hasNotifyContent()) {\n          if (!getNotifyContent().isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ModifyGroupInfoRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string group_id = 1;\n      private java.lang.Object groupId_ = \"\";\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public boolean hasGroupId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public java.lang.String getGroupId() {\n        java.lang.Object ref = groupId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          groupId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getGroupIdBytes() {\n        java.lang.Object ref = groupId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          groupId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder clearGroupId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        groupId_ = getDefaultInstance().getGroupId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 type = 2;\n      private int type_ ;\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00000002;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required string value = 3;\n      private java.lang.Object value_ = \"\";\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public boolean hasValue() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public java.lang.String getValue() {\n        java.lang.Object ref = value_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          value_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getValueBytes() {\n        java.lang.Object ref = value_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          value_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public Builder setValue(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public Builder clearValue() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        value_ = getDefaultInstance().getValue();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public Builder setValueBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n\n      // repeated int32 to_line = 4;\n      private java.util.List<java.lang.Integer> toLine_ = java.util.Collections.emptyList();\n      private void ensureToLineIsMutable() {\n        if (!((bitField0_ & 0x00000008) == 0x00000008)) {\n          toLine_ = new java.util.ArrayList<java.lang.Integer>(toLine_);\n          bitField0_ |= 0x00000008;\n         }\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public java.util.List<java.lang.Integer>\n          getToLineList() {\n        return java.util.Collections.unmodifiableList(toLine_);\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public int getToLineCount() {\n        return toLine_.size();\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public int getToLine(int index) {\n        return toLine_.get(index);\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public Builder setToLine(\n          int index, int value) {\n        ensureToLineIsMutable();\n        toLine_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public Builder addToLine(int value) {\n        ensureToLineIsMutable();\n        toLine_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public Builder addAllToLine(\n          java.lang.Iterable<? extends java.lang.Integer> values) {\n        ensureToLineIsMutable();\n        super.addAll(values, toLine_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public Builder clearToLine() {\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000008);\n        onChanged();\n        return this;\n      }\n\n      // optional .MessageContent notify_content = 5;\n      private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> notifyContentBuilder_;\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public boolean hasNotifyContent() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          return notifyContent_;\n        } else {\n          return notifyContentBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public Builder setNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          notifyContent_ = value;\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000010;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public Builder setNotifyContent(\n          cn.wildfirechat.proto.WFCMessage.MessageContent.Builder builderForValue) {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = builderForValue.build();\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000010;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public Builder mergeNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (((bitField0_ & 0x00000010) == 0x00000010) &&\n              notifyContent_ != cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) {\n            notifyContent_ =\n              cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder(notifyContent_).mergeFrom(value).buildPartial();\n          } else {\n            notifyContent_ = value;\n          }\n          onChanged();\n        } else {\n          notifyContentBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000010;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public Builder clearNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n          onChanged();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000010);\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent.Builder getNotifyContentBuilder() {\n        bitField0_ |= 0x00000010;\n        onChanged();\n        return getNotifyContentFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n        if (notifyContentBuilder_ != null) {\n          return notifyContentBuilder_.getMessageOrBuilder();\n        } else {\n          return notifyContent_;\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> \n          getNotifyContentFieldBuilder() {\n        if (notifyContentBuilder_ == null) {\n          notifyContentBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder>(\n                  notifyContent_,\n                  getParentForChildren(),\n                  isClean());\n          notifyContent_ = null;\n        }\n        return notifyContentBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ModifyGroupInfoRequest)\n    }\n\n    static {\n      defaultInstance = new ModifyGroupInfoRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ModifyGroupInfoRequest)\n  }\n\n  public interface SetGroupManagerRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string group_id = 1;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    boolean hasGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    java.lang.String getGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getGroupIdBytes();\n\n    // required int32 type = 2;\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    int getType();\n\n    // repeated string user_id = 3;\n    /**\n     * <code>repeated string user_id = 3;</code>\n     */\n    java.util.List<java.lang.String>\n    getUserIdList();\n    /**\n     * <code>repeated string user_id = 3;</code>\n     */\n    int getUserIdCount();\n    /**\n     * <code>repeated string user_id = 3;</code>\n     */\n    java.lang.String getUserId(int index);\n    /**\n     * <code>repeated string user_id = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getUserIdBytes(int index);\n\n    // repeated int32 to_line = 4;\n    /**\n     * <code>repeated int32 to_line = 4;</code>\n     */\n    java.util.List<java.lang.Integer> getToLineList();\n    /**\n     * <code>repeated int32 to_line = 4;</code>\n     */\n    int getToLineCount();\n    /**\n     * <code>repeated int32 to_line = 4;</code>\n     */\n    int getToLine(int index);\n\n    // optional .MessageContent notify_content = 5;\n    /**\n     * <code>optional .MessageContent notify_content = 5;</code>\n     */\n    boolean hasNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 5;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 5;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder();\n  }\n  /**\n   * Protobuf type {@code SetGroupManagerRequest}\n   */\n  public static final class SetGroupManagerRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements SetGroupManagerRequestOrBuilder {\n    // Use SetGroupManagerRequest.newBuilder() to construct.\n    private SetGroupManagerRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private SetGroupManagerRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final SetGroupManagerRequest defaultInstance;\n    public static SetGroupManagerRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public SetGroupManagerRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private SetGroupManagerRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              groupId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              type_ = input.readInt32();\n              break;\n            }\n            case 26: {\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n                userId_ = new com.google.protobuf.LazyStringArrayList();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              userId_.add(input.readBytes());\n              break;\n            }\n            case 32: {\n              if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000008;\n              }\n              toLine_.add(input.readInt32());\n              break;\n            }\n            case 34: {\n              int length = input.readRawVarint32();\n              int limit = input.pushLimit(length);\n              if (!((mutable_bitField0_ & 0x00000008) == 0x00000008) && input.getBytesUntilLimit() > 0) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000008;\n              }\n              while (input.getBytesUntilLimit() > 0) {\n                toLine_.add(input.readInt32());\n              }\n              input.popLimit(limit);\n              break;\n            }\n            case 42: {\n              cn.wildfirechat.proto.WFCMessage.MessageContent.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000004) == 0x00000004)) {\n                subBuilder = notifyContent_.toBuilder();\n              }\n              notifyContent_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.MessageContent.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(notifyContent_);\n                notifyContent_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000004;\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n          userId_ = new com.google.protobuf.UnmodifiableLazyStringList(userId_);\n        }\n        if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_SetGroupManagerRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_SetGroupManagerRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest.class, cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<SetGroupManagerRequest> PARSER =\n        new com.google.protobuf.AbstractParser<SetGroupManagerRequest>() {\n      public SetGroupManagerRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new SetGroupManagerRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<SetGroupManagerRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string group_id = 1;\n    public static final int GROUP_ID_FIELD_NUMBER = 1;\n    private java.lang.Object groupId_;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public boolean hasGroupId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public java.lang.String getGroupId() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          groupId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getGroupIdBytes() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        groupId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 type = 2;\n    public static final int TYPE_FIELD_NUMBER = 2;\n    private int type_;\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    // repeated string user_id = 3;\n    public static final int USER_ID_FIELD_NUMBER = 3;\n    private com.google.protobuf.LazyStringList userId_;\n    /**\n     * <code>repeated string user_id = 3;</code>\n     */\n    public java.util.List<java.lang.String>\n        getUserIdList() {\n      return userId_;\n    }\n    /**\n     * <code>repeated string user_id = 3;</code>\n     */\n    public int getUserIdCount() {\n      return userId_.size();\n    }\n    /**\n     * <code>repeated string user_id = 3;</code>\n     */\n    public java.lang.String getUserId(int index) {\n      return userId_.get(index);\n    }\n    /**\n     * <code>repeated string user_id = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getUserIdBytes(int index) {\n      return userId_.getByteString(index);\n    }\n\n    // repeated int32 to_line = 4;\n    public static final int TO_LINE_FIELD_NUMBER = 4;\n    private java.util.List<java.lang.Integer> toLine_;\n    /**\n     * <code>repeated int32 to_line = 4;</code>\n     */\n    public java.util.List<java.lang.Integer>\n        getToLineList() {\n      return toLine_;\n    }\n    /**\n     * <code>repeated int32 to_line = 4;</code>\n     */\n    public int getToLineCount() {\n      return toLine_.size();\n    }\n    /**\n     * <code>repeated int32 to_line = 4;</code>\n     */\n    public int getToLine(int index) {\n      return toLine_.get(index);\n    }\n\n    // optional .MessageContent notify_content = 5;\n    public static final int NOTIFY_CONTENT_FIELD_NUMBER = 5;\n    private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_;\n    /**\n     * <code>optional .MessageContent notify_content = 5;</code>\n     */\n    public boolean hasNotifyContent() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 5;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n      return notifyContent_;\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 5;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n      return notifyContent_;\n    }\n\n    private void initFields() {\n      groupId_ = \"\";\n      type_ = 0;\n      userId_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      toLine_ = java.util.Collections.emptyList();\n      notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasGroupId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (hasNotifyContent()) {\n        if (!getNotifyContent().isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getGroupIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, type_);\n      }\n      for (int i = 0; i < userId_.size(); i++) {\n        output.writeBytes(3, userId_.getByteString(i));\n      }\n      for (int i = 0; i < toLine_.size(); i++) {\n        output.writeInt32(4, toLine_.get(i));\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeMessage(5, notifyContent_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getGroupIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, type_);\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < userId_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeBytesSizeNoTag(userId_.getByteString(i));\n        }\n        size += dataSize;\n        size += 1 * getUserIdList().size();\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < toLine_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeInt32SizeNoTag(toLine_.get(i));\n        }\n        size += dataSize;\n        size += 1 * getToLineList().size();\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(5, notifyContent_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code SetGroupManagerRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_SetGroupManagerRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_SetGroupManagerRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest.class, cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getNotifyContentFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        groupId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        userId_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000008);\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000010);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_SetGroupManagerRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest build() {\n        cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest result = new cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.groupId_ = groupId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.type_ = type_;\n        if (((bitField0_ & 0x00000004) == 0x00000004)) {\n          userId_ = new com.google.protobuf.UnmodifiableLazyStringList(\n              userId_);\n          bitField0_ = (bitField0_ & ~0x00000004);\n        }\n        result.userId_ = userId_;\n        if (((bitField0_ & 0x00000008) == 0x00000008)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n          bitField0_ = (bitField0_ & ~0x00000008);\n        }\n        result.toLine_ = toLine_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        if (notifyContentBuilder_ == null) {\n          result.notifyContent_ = notifyContent_;\n        } else {\n          result.notifyContent_ = notifyContentBuilder_.build();\n        }\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest.getDefaultInstance()) return this;\n        if (other.hasGroupId()) {\n          bitField0_ |= 0x00000001;\n          groupId_ = other.groupId_;\n          onChanged();\n        }\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        if (!other.userId_.isEmpty()) {\n          if (userId_.isEmpty()) {\n            userId_ = other.userId_;\n            bitField0_ = (bitField0_ & ~0x00000004);\n          } else {\n            ensureUserIdIsMutable();\n            userId_.addAll(other.userId_);\n          }\n          onChanged();\n        }\n        if (!other.toLine_.isEmpty()) {\n          if (toLine_.isEmpty()) {\n            toLine_ = other.toLine_;\n            bitField0_ = (bitField0_ & ~0x00000008);\n          } else {\n            ensureToLineIsMutable();\n            toLine_.addAll(other.toLine_);\n          }\n          onChanged();\n        }\n        if (other.hasNotifyContent()) {\n          mergeNotifyContent(other.getNotifyContent());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasGroupId()) {\n          \n          return false;\n        }\n        if (!hasType()) {\n          \n          return false;\n        }\n        if (hasNotifyContent()) {\n          if (!getNotifyContent().isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.SetGroupManagerRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string group_id = 1;\n      private java.lang.Object groupId_ = \"\";\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public boolean hasGroupId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public java.lang.String getGroupId() {\n        java.lang.Object ref = groupId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          groupId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getGroupIdBytes() {\n        java.lang.Object ref = groupId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          groupId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder clearGroupId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        groupId_ = getDefaultInstance().getGroupId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 type = 2;\n      private int type_ ;\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00000002;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // repeated string user_id = 3;\n      private com.google.protobuf.LazyStringList userId_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      private void ensureUserIdIsMutable() {\n        if (!((bitField0_ & 0x00000004) == 0x00000004)) {\n          userId_ = new com.google.protobuf.LazyStringArrayList(userId_);\n          bitField0_ |= 0x00000004;\n         }\n      }\n      /**\n       * <code>repeated string user_id = 3;</code>\n       */\n      public java.util.List<java.lang.String>\n          getUserIdList() {\n        return java.util.Collections.unmodifiableList(userId_);\n      }\n      /**\n       * <code>repeated string user_id = 3;</code>\n       */\n      public int getUserIdCount() {\n        return userId_.size();\n      }\n      /**\n       * <code>repeated string user_id = 3;</code>\n       */\n      public java.lang.String getUserId(int index) {\n        return userId_.get(index);\n      }\n      /**\n       * <code>repeated string user_id = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getUserIdBytes(int index) {\n        return userId_.getByteString(index);\n      }\n      /**\n       * <code>repeated string user_id = 3;</code>\n       */\n      public Builder setUserId(\n          int index, java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureUserIdIsMutable();\n        userId_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string user_id = 3;</code>\n       */\n      public Builder addUserId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureUserIdIsMutable();\n        userId_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string user_id = 3;</code>\n       */\n      public Builder addAllUserId(\n          java.lang.Iterable<java.lang.String> values) {\n        ensureUserIdIsMutable();\n        super.addAll(values, userId_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string user_id = 3;</code>\n       */\n      public Builder clearUserId() {\n        userId_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string user_id = 3;</code>\n       */\n      public Builder addUserIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureUserIdIsMutable();\n        userId_.add(value);\n        onChanged();\n        return this;\n      }\n\n      // repeated int32 to_line = 4;\n      private java.util.List<java.lang.Integer> toLine_ = java.util.Collections.emptyList();\n      private void ensureToLineIsMutable() {\n        if (!((bitField0_ & 0x00000008) == 0x00000008)) {\n          toLine_ = new java.util.ArrayList<java.lang.Integer>(toLine_);\n          bitField0_ |= 0x00000008;\n         }\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public java.util.List<java.lang.Integer>\n          getToLineList() {\n        return java.util.Collections.unmodifiableList(toLine_);\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public int getToLineCount() {\n        return toLine_.size();\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public int getToLine(int index) {\n        return toLine_.get(index);\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public Builder setToLine(\n          int index, int value) {\n        ensureToLineIsMutable();\n        toLine_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public Builder addToLine(int value) {\n        ensureToLineIsMutable();\n        toLine_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public Builder addAllToLine(\n          java.lang.Iterable<? extends java.lang.Integer> values) {\n        ensureToLineIsMutable();\n        super.addAll(values, toLine_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 4;</code>\n       */\n      public Builder clearToLine() {\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000008);\n        onChanged();\n        return this;\n      }\n\n      // optional .MessageContent notify_content = 5;\n      private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> notifyContentBuilder_;\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public boolean hasNotifyContent() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          return notifyContent_;\n        } else {\n          return notifyContentBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public Builder setNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          notifyContent_ = value;\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000010;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public Builder setNotifyContent(\n          cn.wildfirechat.proto.WFCMessage.MessageContent.Builder builderForValue) {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = builderForValue.build();\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000010;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public Builder mergeNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (((bitField0_ & 0x00000010) == 0x00000010) &&\n              notifyContent_ != cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) {\n            notifyContent_ =\n              cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder(notifyContent_).mergeFrom(value).buildPartial();\n          } else {\n            notifyContent_ = value;\n          }\n          onChanged();\n        } else {\n          notifyContentBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000010;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public Builder clearNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n          onChanged();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000010);\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent.Builder getNotifyContentBuilder() {\n        bitField0_ |= 0x00000010;\n        onChanged();\n        return getNotifyContentFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n        if (notifyContentBuilder_ != null) {\n          return notifyContentBuilder_.getMessageOrBuilder();\n        } else {\n          return notifyContent_;\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 5;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> \n          getNotifyContentFieldBuilder() {\n        if (notifyContentBuilder_ == null) {\n          notifyContentBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder>(\n                  notifyContent_,\n                  getParentForChildren(),\n                  isClean());\n          notifyContent_ = null;\n        }\n        return notifyContentBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:SetGroupManagerRequest)\n    }\n\n    static {\n      defaultInstance = new SetGroupManagerRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:SetGroupManagerRequest)\n  }\n\n  public interface InfoEntryOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int32 type = 1;\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    int getType();\n\n    // required string value = 2;\n    /**\n     * <code>required string value = 2;</code>\n     */\n    boolean hasValue();\n    /**\n     * <code>required string value = 2;</code>\n     */\n    java.lang.String getValue();\n    /**\n     * <code>required string value = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getValueBytes();\n  }\n  /**\n   * Protobuf type {@code InfoEntry}\n   */\n  public static final class InfoEntry extends\n      com.google.protobuf.GeneratedMessage\n      implements InfoEntryOrBuilder {\n    // Use InfoEntry.newBuilder() to construct.\n    private InfoEntry(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private InfoEntry(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final InfoEntry defaultInstance;\n    public static InfoEntry getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public InfoEntry getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private InfoEntry(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              type_ = input.readInt32();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              value_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_InfoEntry_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_InfoEntry_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.InfoEntry.class, cn.wildfirechat.proto.WFCMessage.InfoEntry.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<InfoEntry> PARSER =\n        new com.google.protobuf.AbstractParser<InfoEntry>() {\n      public InfoEntry parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new InfoEntry(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<InfoEntry> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int32 type = 1;\n    public static final int TYPE_FIELD_NUMBER = 1;\n    private int type_;\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    // required string value = 2;\n    public static final int VALUE_FIELD_NUMBER = 2;\n    private java.lang.Object value_;\n    /**\n     * <code>required string value = 2;</code>\n     */\n    public boolean hasValue() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string value = 2;</code>\n     */\n    public java.lang.String getValue() {\n      java.lang.Object ref = value_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          value_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string value = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getValueBytes() {\n      java.lang.Object ref = value_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        value_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      type_ = 0;\n      value_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasValue()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, type_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getValueBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, type_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getValueBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.InfoEntry parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.InfoEntry parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.InfoEntry parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.InfoEntry parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.InfoEntry parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.InfoEntry parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.InfoEntry parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.InfoEntry parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.InfoEntry parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.InfoEntry parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.InfoEntry prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code InfoEntry}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.InfoEntryOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_InfoEntry_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_InfoEntry_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.InfoEntry.class, cn.wildfirechat.proto.WFCMessage.InfoEntry.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.InfoEntry.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        value_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_InfoEntry_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.InfoEntry getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.InfoEntry.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.InfoEntry build() {\n        cn.wildfirechat.proto.WFCMessage.InfoEntry result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.InfoEntry buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.InfoEntry result = new cn.wildfirechat.proto.WFCMessage.InfoEntry(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.type_ = type_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.value_ = value_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.InfoEntry) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.InfoEntry)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.InfoEntry other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.InfoEntry.getDefaultInstance()) return this;\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        if (other.hasValue()) {\n          bitField0_ |= 0x00000002;\n          value_ = other.value_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasType()) {\n          \n          return false;\n        }\n        if (!hasValue()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.InfoEntry parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.InfoEntry) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int32 type = 1;\n      private int type_ ;\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00000001;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required string value = 2;\n      private java.lang.Object value_ = \"\";\n      /**\n       * <code>required string value = 2;</code>\n       */\n      public boolean hasValue() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string value = 2;</code>\n       */\n      public java.lang.String getValue() {\n        java.lang.Object ref = value_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          value_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string value = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getValueBytes() {\n        java.lang.Object ref = value_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          value_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string value = 2;</code>\n       */\n      public Builder setValue(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string value = 2;</code>\n       */\n      public Builder clearValue() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        value_ = getDefaultInstance().getValue();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string value = 2;</code>\n       */\n      public Builder setValueBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:InfoEntry)\n    }\n\n    static {\n      defaultInstance = new InfoEntry(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:InfoEntry)\n  }\n\n  public interface ModifyMyInfoRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .InfoEntry entry = 1;\n    /**\n     * <code>repeated .InfoEntry entry = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.InfoEntry> \n        getEntryList();\n    /**\n     * <code>repeated .InfoEntry entry = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.InfoEntry getEntry(int index);\n    /**\n     * <code>repeated .InfoEntry entry = 1;</code>\n     */\n    int getEntryCount();\n    /**\n     * <code>repeated .InfoEntry entry = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.InfoEntryOrBuilder> \n        getEntryOrBuilderList();\n    /**\n     * <code>repeated .InfoEntry entry = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.InfoEntryOrBuilder getEntryOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code ModifyMyInfoRequest}\n   */\n  public static final class ModifyMyInfoRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements ModifyMyInfoRequestOrBuilder {\n    // Use ModifyMyInfoRequest.newBuilder() to construct.\n    private ModifyMyInfoRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ModifyMyInfoRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ModifyMyInfoRequest defaultInstance;\n    public static ModifyMyInfoRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ModifyMyInfoRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ModifyMyInfoRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                entry_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.InfoEntry>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              entry_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.InfoEntry.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          entry_ = java.util.Collections.unmodifiableList(entry_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyMyInfoRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyMyInfoRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest.class, cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ModifyMyInfoRequest> PARSER =\n        new com.google.protobuf.AbstractParser<ModifyMyInfoRequest>() {\n      public ModifyMyInfoRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ModifyMyInfoRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ModifyMyInfoRequest> getParserForType() {\n      return PARSER;\n    }\n\n    // repeated .InfoEntry entry = 1;\n    public static final int ENTRY_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.InfoEntry> entry_;\n    /**\n     * <code>repeated .InfoEntry entry = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.InfoEntry> getEntryList() {\n      return entry_;\n    }\n    /**\n     * <code>repeated .InfoEntry entry = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.InfoEntryOrBuilder> \n        getEntryOrBuilderList() {\n      return entry_;\n    }\n    /**\n     * <code>repeated .InfoEntry entry = 1;</code>\n     */\n    public int getEntryCount() {\n      return entry_.size();\n    }\n    /**\n     * <code>repeated .InfoEntry entry = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.InfoEntry getEntry(int index) {\n      return entry_.get(index);\n    }\n    /**\n     * <code>repeated .InfoEntry entry = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.InfoEntryOrBuilder getEntryOrBuilder(\n        int index) {\n      return entry_.get(index);\n    }\n\n    private void initFields() {\n      entry_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      for (int i = 0; i < getEntryCount(); i++) {\n        if (!getEntry(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < entry_.size(); i++) {\n        output.writeMessage(1, entry_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < entry_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, entry_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ModifyMyInfoRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyMyInfoRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyMyInfoRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest.class, cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getEntryFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (entryBuilder_ == null) {\n          entry_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          entryBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyMyInfoRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest build() {\n        cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest result = new cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest(this);\n        int from_bitField0_ = bitField0_;\n        if (entryBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            entry_ = java.util.Collections.unmodifiableList(entry_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.entry_ = entry_;\n        } else {\n          result.entry_ = entryBuilder_.build();\n        }\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest.getDefaultInstance()) return this;\n        if (entryBuilder_ == null) {\n          if (!other.entry_.isEmpty()) {\n            if (entry_.isEmpty()) {\n              entry_ = other.entry_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureEntryIsMutable();\n              entry_.addAll(other.entry_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.entry_.isEmpty()) {\n            if (entryBuilder_.isEmpty()) {\n              entryBuilder_.dispose();\n              entryBuilder_ = null;\n              entry_ = other.entry_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              entryBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getEntryFieldBuilder() : null;\n            } else {\n              entryBuilder_.addAllMessages(other.entry_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        for (int i = 0; i < getEntryCount(); i++) {\n          if (!getEntry(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ModifyMyInfoRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .InfoEntry entry = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.InfoEntry> entry_ =\n        java.util.Collections.emptyList();\n      private void ensureEntryIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          entry_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.InfoEntry>(entry_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.InfoEntry, cn.wildfirechat.proto.WFCMessage.InfoEntry.Builder, cn.wildfirechat.proto.WFCMessage.InfoEntryOrBuilder> entryBuilder_;\n\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.InfoEntry> getEntryList() {\n        if (entryBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(entry_);\n        } else {\n          return entryBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public int getEntryCount() {\n        if (entryBuilder_ == null) {\n          return entry_.size();\n        } else {\n          return entryBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.InfoEntry getEntry(int index) {\n        if (entryBuilder_ == null) {\n          return entry_.get(index);\n        } else {\n          return entryBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public Builder setEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.InfoEntry value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.set(index, value);\n          onChanged();\n        } else {\n          entryBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public Builder setEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.InfoEntry.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public Builder addEntry(cn.wildfirechat.proto.WFCMessage.InfoEntry value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.add(value);\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public Builder addEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.InfoEntry value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.add(index, value);\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public Builder addEntry(\n          cn.wildfirechat.proto.WFCMessage.InfoEntry.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.add(builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public Builder addEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.InfoEntry.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public Builder addAllEntry(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.InfoEntry> values) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          super.addAll(values, entry_);\n          onChanged();\n        } else {\n          entryBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public Builder clearEntry() {\n        if (entryBuilder_ == null) {\n          entry_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          entryBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public Builder removeEntry(int index) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.remove(index);\n          onChanged();\n        } else {\n          entryBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.InfoEntry.Builder getEntryBuilder(\n          int index) {\n        return getEntryFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.InfoEntryOrBuilder getEntryOrBuilder(\n          int index) {\n        if (entryBuilder_ == null) {\n          return entry_.get(index);  } else {\n          return entryBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.InfoEntryOrBuilder> \n           getEntryOrBuilderList() {\n        if (entryBuilder_ != null) {\n          return entryBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(entry_);\n        }\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.InfoEntry.Builder addEntryBuilder() {\n        return getEntryFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.InfoEntry.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.InfoEntry.Builder addEntryBuilder(\n          int index) {\n        return getEntryFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.InfoEntry.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .InfoEntry entry = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.InfoEntry.Builder> \n           getEntryBuilderList() {\n        return getEntryFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.InfoEntry, cn.wildfirechat.proto.WFCMessage.InfoEntry.Builder, cn.wildfirechat.proto.WFCMessage.InfoEntryOrBuilder> \n          getEntryFieldBuilder() {\n        if (entryBuilder_ == null) {\n          entryBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.InfoEntry, cn.wildfirechat.proto.WFCMessage.InfoEntry.Builder, cn.wildfirechat.proto.WFCMessage.InfoEntryOrBuilder>(\n                  entry_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          entry_ = null;\n        }\n        return entryBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ModifyMyInfoRequest)\n    }\n\n    static {\n      defaultInstance = new ModifyMyInfoRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ModifyMyInfoRequest)\n  }\n\n  public interface NotifyMessageOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int32 type = 1;\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    int getType();\n\n    // required int64 head = 2;\n    /**\n     * <code>required int64 head = 2;</code>\n     */\n    boolean hasHead();\n    /**\n     * <code>required int64 head = 2;</code>\n     */\n    long getHead();\n\n    // optional string target = 3;\n    /**\n     * <code>optional string target = 3;</code>\n     */\n    boolean hasTarget();\n    /**\n     * <code>optional string target = 3;</code>\n     */\n    java.lang.String getTarget();\n    /**\n     * <code>optional string target = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getTargetBytes();\n  }\n  /**\n   * Protobuf type {@code NotifyMessage}\n   */\n  public static final class NotifyMessage extends\n      com.google.protobuf.GeneratedMessage\n      implements NotifyMessageOrBuilder {\n    // Use NotifyMessage.newBuilder() to construct.\n    private NotifyMessage(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private NotifyMessage(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final NotifyMessage defaultInstance;\n    public static NotifyMessage getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public NotifyMessage getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private NotifyMessage(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              type_ = input.readInt32();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              head_ = input.readInt64();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              target_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_NotifyMessage_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_NotifyMessage_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.NotifyMessage.class, cn.wildfirechat.proto.WFCMessage.NotifyMessage.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<NotifyMessage> PARSER =\n        new com.google.protobuf.AbstractParser<NotifyMessage>() {\n      public NotifyMessage parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new NotifyMessage(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<NotifyMessage> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int32 type = 1;\n    public static final int TYPE_FIELD_NUMBER = 1;\n    private int type_;\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int32 type = 1;</code>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    // required int64 head = 2;\n    public static final int HEAD_FIELD_NUMBER = 2;\n    private long head_;\n    /**\n     * <code>required int64 head = 2;</code>\n     */\n    public boolean hasHead() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int64 head = 2;</code>\n     */\n    public long getHead() {\n      return head_;\n    }\n\n    // optional string target = 3;\n    public static final int TARGET_FIELD_NUMBER = 3;\n    private java.lang.Object target_;\n    /**\n     * <code>optional string target = 3;</code>\n     */\n    public boolean hasTarget() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string target = 3;</code>\n     */\n    public java.lang.String getTarget() {\n      java.lang.Object ref = target_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          target_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string target = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTargetBytes() {\n      java.lang.Object ref = target_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        target_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      type_ = 0;\n      head_ = 0L;\n      target_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasHead()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, type_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt64(2, head_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getTargetBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, type_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(2, head_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getTargetBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.NotifyMessage parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyMessage parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyMessage parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyMessage parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyMessage parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyMessage parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyMessage parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyMessage parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyMessage parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyMessage parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.NotifyMessage prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code NotifyMessage}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.NotifyMessageOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_NotifyMessage_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_NotifyMessage_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.NotifyMessage.class, cn.wildfirechat.proto.WFCMessage.NotifyMessage.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.NotifyMessage.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        head_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        target_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_NotifyMessage_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.NotifyMessage getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.NotifyMessage.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.NotifyMessage build() {\n        cn.wildfirechat.proto.WFCMessage.NotifyMessage result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.NotifyMessage buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.NotifyMessage result = new cn.wildfirechat.proto.WFCMessage.NotifyMessage(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.type_ = type_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.head_ = head_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.target_ = target_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.NotifyMessage) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.NotifyMessage)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.NotifyMessage other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.NotifyMessage.getDefaultInstance()) return this;\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        if (other.hasHead()) {\n          setHead(other.getHead());\n        }\n        if (other.hasTarget()) {\n          bitField0_ |= 0x00000004;\n          target_ = other.target_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasType()) {\n          \n          return false;\n        }\n        if (!hasHead()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.NotifyMessage parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.NotifyMessage) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int32 type = 1;\n      private int type_ ;\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00000001;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 type = 1;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required int64 head = 2;\n      private long head_ ;\n      /**\n       * <code>required int64 head = 2;</code>\n       */\n      public boolean hasHead() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int64 head = 2;</code>\n       */\n      public long getHead() {\n        return head_;\n      }\n      /**\n       * <code>required int64 head = 2;</code>\n       */\n      public Builder setHead(long value) {\n        bitField0_ |= 0x00000002;\n        head_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 head = 2;</code>\n       */\n      public Builder clearHead() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        head_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional string target = 3;\n      private java.lang.Object target_ = \"\";\n      /**\n       * <code>optional string target = 3;</code>\n       */\n      public boolean hasTarget() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional string target = 3;</code>\n       */\n      public java.lang.String getTarget() {\n        java.lang.Object ref = target_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          target_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string target = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTargetBytes() {\n        java.lang.Object ref = target_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          target_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string target = 3;</code>\n       */\n      public Builder setTarget(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        target_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string target = 3;</code>\n       */\n      public Builder clearTarget() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        target_ = getDefaultInstance().getTarget();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string target = 3;</code>\n       */\n      public Builder setTargetBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        target_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:NotifyMessage)\n    }\n\n    static {\n      defaultInstance = new NotifyMessage(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:NotifyMessage)\n  }\n\n  public interface PullMessageRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int64 id = 1;\n    /**\n     * <code>required int64 id = 1;</code>\n     */\n    boolean hasId();\n    /**\n     * <code>required int64 id = 1;</code>\n     */\n    long getId();\n\n    // required int32 type = 2;\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    int getType();\n\n    // optional int64 delay = 3;\n    /**\n     * <code>optional int64 delay = 3;</code>\n     */\n    boolean hasDelay();\n    /**\n     * <code>optional int64 delay = 3;</code>\n     */\n    long getDelay();\n  }\n  /**\n   * Protobuf type {@code PullMessageRequest}\n   */\n  public static final class PullMessageRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements PullMessageRequestOrBuilder {\n    // Use PullMessageRequest.newBuilder() to construct.\n    private PullMessageRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private PullMessageRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final PullMessageRequest defaultInstance;\n    public static PullMessageRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public PullMessageRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private PullMessageRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              id_ = input.readInt64();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              type_ = input.readInt32();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              delay_ = input.readInt64();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullMessageRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullMessageRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.PullMessageRequest.class, cn.wildfirechat.proto.WFCMessage.PullMessageRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<PullMessageRequest> PARSER =\n        new com.google.protobuf.AbstractParser<PullMessageRequest>() {\n      public PullMessageRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new PullMessageRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<PullMessageRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int64 id = 1;\n    public static final int ID_FIELD_NUMBER = 1;\n    private long id_;\n    /**\n     * <code>required int64 id = 1;</code>\n     */\n    public boolean hasId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int64 id = 1;</code>\n     */\n    public long getId() {\n      return id_;\n    }\n\n    // required int32 type = 2;\n    public static final int TYPE_FIELD_NUMBER = 2;\n    private int type_;\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    // optional int64 delay = 3;\n    public static final int DELAY_FIELD_NUMBER = 3;\n    private long delay_;\n    /**\n     * <code>optional int64 delay = 3;</code>\n     */\n    public boolean hasDelay() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional int64 delay = 3;</code>\n     */\n    public long getDelay() {\n      return delay_;\n    }\n\n    private void initFields() {\n      id_ = 0L;\n      type_ = 0;\n      delay_ = 0L;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt64(1, id_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, type_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt64(3, delay_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, id_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, type_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(3, delay_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.PullMessageRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code PullMessageRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.PullMessageRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullMessageRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullMessageRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.PullMessageRequest.class, cn.wildfirechat.proto.WFCMessage.PullMessageRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.PullMessageRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        id_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        delay_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullMessageRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullMessageRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.PullMessageRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullMessageRequest build() {\n        cn.wildfirechat.proto.WFCMessage.PullMessageRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullMessageRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.PullMessageRequest result = new cn.wildfirechat.proto.WFCMessage.PullMessageRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.id_ = id_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.type_ = type_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.delay_ = delay_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.PullMessageRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.PullMessageRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.PullMessageRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.PullMessageRequest.getDefaultInstance()) return this;\n        if (other.hasId()) {\n          setId(other.getId());\n        }\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        if (other.hasDelay()) {\n          setDelay(other.getDelay());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasId()) {\n          \n          return false;\n        }\n        if (!hasType()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.PullMessageRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.PullMessageRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int64 id = 1;\n      private long id_ ;\n      /**\n       * <code>required int64 id = 1;</code>\n       */\n      public boolean hasId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int64 id = 1;</code>\n       */\n      public long getId() {\n        return id_;\n      }\n      /**\n       * <code>required int64 id = 1;</code>\n       */\n      public Builder setId(long value) {\n        bitField0_ |= 0x00000001;\n        id_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 id = 1;</code>\n       */\n      public Builder clearId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        id_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // required int32 type = 2;\n      private int type_ ;\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00000002;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 delay = 3;\n      private long delay_ ;\n      /**\n       * <code>optional int64 delay = 3;</code>\n       */\n      public boolean hasDelay() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional int64 delay = 3;</code>\n       */\n      public long getDelay() {\n        return delay_;\n      }\n      /**\n       * <code>optional int64 delay = 3;</code>\n       */\n      public Builder setDelay(long value) {\n        bitField0_ |= 0x00000004;\n        delay_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 delay = 3;</code>\n       */\n      public Builder clearDelay() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        delay_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:PullMessageRequest)\n    }\n\n    static {\n      defaultInstance = new PullMessageRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:PullMessageRequest)\n  }\n\n  public interface PullMessageResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .Message message = 1;\n    /**\n     * <code>repeated .Message message = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.Message> \n        getMessageList();\n    /**\n     * <code>repeated .Message message = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.Message getMessage(int index);\n    /**\n     * <code>repeated .Message message = 1;</code>\n     */\n    int getMessageCount();\n    /**\n     * <code>repeated .Message message = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.MessageOrBuilder> \n        getMessageOrBuilderList();\n    /**\n     * <code>repeated .Message message = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageOrBuilder getMessageOrBuilder(\n        int index);\n\n    // required int64 current = 2;\n    /**\n     * <code>required int64 current = 2;</code>\n     */\n    boolean hasCurrent();\n    /**\n     * <code>required int64 current = 2;</code>\n     */\n    long getCurrent();\n\n    // required int64 head = 3;\n    /**\n     * <code>required int64 head = 3;</code>\n     */\n    boolean hasHead();\n    /**\n     * <code>required int64 head = 3;</code>\n     */\n    long getHead();\n  }\n  /**\n   * Protobuf type {@code PullMessageResult}\n   */\n  public static final class PullMessageResult extends\n      com.google.protobuf.GeneratedMessage\n      implements PullMessageResultOrBuilder {\n    // Use PullMessageResult.newBuilder() to construct.\n    private PullMessageResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private PullMessageResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final PullMessageResult defaultInstance;\n    public static PullMessageResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public PullMessageResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private PullMessageResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                message_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.Message>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              message_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.Message.PARSER, extensionRegistry));\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000001;\n              current_ = input.readInt64();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000002;\n              head_ = input.readInt64();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          message_ = java.util.Collections.unmodifiableList(message_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullMessageResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullMessageResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.PullMessageResult.class, cn.wildfirechat.proto.WFCMessage.PullMessageResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<PullMessageResult> PARSER =\n        new com.google.protobuf.AbstractParser<PullMessageResult>() {\n      public PullMessageResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new PullMessageResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<PullMessageResult> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // repeated .Message message = 1;\n    public static final int MESSAGE_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.Message> message_;\n    /**\n     * <code>repeated .Message message = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.Message> getMessageList() {\n      return message_;\n    }\n    /**\n     * <code>repeated .Message message = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.MessageOrBuilder> \n        getMessageOrBuilderList() {\n      return message_;\n    }\n    /**\n     * <code>repeated .Message message = 1;</code>\n     */\n    public int getMessageCount() {\n      return message_.size();\n    }\n    /**\n     * <code>repeated .Message message = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.Message getMessage(int index) {\n      return message_.get(index);\n    }\n    /**\n     * <code>repeated .Message message = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageOrBuilder getMessageOrBuilder(\n        int index) {\n      return message_.get(index);\n    }\n\n    // required int64 current = 2;\n    public static final int CURRENT_FIELD_NUMBER = 2;\n    private long current_;\n    /**\n     * <code>required int64 current = 2;</code>\n     */\n    public boolean hasCurrent() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int64 current = 2;</code>\n     */\n    public long getCurrent() {\n      return current_;\n    }\n\n    // required int64 head = 3;\n    public static final int HEAD_FIELD_NUMBER = 3;\n    private long head_;\n    /**\n     * <code>required int64 head = 3;</code>\n     */\n    public boolean hasHead() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int64 head = 3;</code>\n     */\n    public long getHead() {\n      return head_;\n    }\n\n    private void initFields() {\n      message_ = java.util.Collections.emptyList();\n      current_ = 0L;\n      head_ = 0L;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasCurrent()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasHead()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      for (int i = 0; i < getMessageCount(); i++) {\n        if (!getMessage(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < message_.size(); i++) {\n        output.writeMessage(1, message_.get(i));\n      }\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt64(2, current_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt64(3, head_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < message_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, message_.get(i));\n      }\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(2, current_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(3, head_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullMessageResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.PullMessageResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code PullMessageResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.PullMessageResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullMessageResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullMessageResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.PullMessageResult.class, cn.wildfirechat.proto.WFCMessage.PullMessageResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.PullMessageResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getMessageFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (messageBuilder_ == null) {\n          message_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          messageBuilder_.clear();\n        }\n        current_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        head_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullMessageResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullMessageResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.PullMessageResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullMessageResult build() {\n        cn.wildfirechat.proto.WFCMessage.PullMessageResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullMessageResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.PullMessageResult result = new cn.wildfirechat.proto.WFCMessage.PullMessageResult(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (messageBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            message_ = java.util.Collections.unmodifiableList(message_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.message_ = message_;\n        } else {\n          result.message_ = messageBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.current_ = current_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.head_ = head_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.PullMessageResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.PullMessageResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.PullMessageResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.PullMessageResult.getDefaultInstance()) return this;\n        if (messageBuilder_ == null) {\n          if (!other.message_.isEmpty()) {\n            if (message_.isEmpty()) {\n              message_ = other.message_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureMessageIsMutable();\n              message_.addAll(other.message_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.message_.isEmpty()) {\n            if (messageBuilder_.isEmpty()) {\n              messageBuilder_.dispose();\n              messageBuilder_ = null;\n              message_ = other.message_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              messageBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getMessageFieldBuilder() : null;\n            } else {\n              messageBuilder_.addAllMessages(other.message_);\n            }\n          }\n        }\n        if (other.hasCurrent()) {\n          setCurrent(other.getCurrent());\n        }\n        if (other.hasHead()) {\n          setHead(other.getHead());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasCurrent()) {\n          \n          return false;\n        }\n        if (!hasHead()) {\n          \n          return false;\n        }\n        for (int i = 0; i < getMessageCount(); i++) {\n          if (!getMessage(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.PullMessageResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.PullMessageResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .Message message = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.Message> message_ =\n        java.util.Collections.emptyList();\n      private void ensureMessageIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          message_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.Message>(message_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.Message, cn.wildfirechat.proto.WFCMessage.Message.Builder, cn.wildfirechat.proto.WFCMessage.MessageOrBuilder> messageBuilder_;\n\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.Message> getMessageList() {\n        if (messageBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(message_);\n        } else {\n          return messageBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public int getMessageCount() {\n        if (messageBuilder_ == null) {\n          return message_.size();\n        } else {\n          return messageBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Message getMessage(int index) {\n        if (messageBuilder_ == null) {\n          return message_.get(index);\n        } else {\n          return messageBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public Builder setMessage(\n          int index, cn.wildfirechat.proto.WFCMessage.Message value) {\n        if (messageBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMessageIsMutable();\n          message_.set(index, value);\n          onChanged();\n        } else {\n          messageBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public Builder setMessage(\n          int index, cn.wildfirechat.proto.WFCMessage.Message.Builder builderForValue) {\n        if (messageBuilder_ == null) {\n          ensureMessageIsMutable();\n          message_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          messageBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public Builder addMessage(cn.wildfirechat.proto.WFCMessage.Message value) {\n        if (messageBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMessageIsMutable();\n          message_.add(value);\n          onChanged();\n        } else {\n          messageBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public Builder addMessage(\n          int index, cn.wildfirechat.proto.WFCMessage.Message value) {\n        if (messageBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMessageIsMutable();\n          message_.add(index, value);\n          onChanged();\n        } else {\n          messageBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public Builder addMessage(\n          cn.wildfirechat.proto.WFCMessage.Message.Builder builderForValue) {\n        if (messageBuilder_ == null) {\n          ensureMessageIsMutable();\n          message_.add(builderForValue.build());\n          onChanged();\n        } else {\n          messageBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public Builder addMessage(\n          int index, cn.wildfirechat.proto.WFCMessage.Message.Builder builderForValue) {\n        if (messageBuilder_ == null) {\n          ensureMessageIsMutable();\n          message_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          messageBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public Builder addAllMessage(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.Message> values) {\n        if (messageBuilder_ == null) {\n          ensureMessageIsMutable();\n          super.addAll(values, message_);\n          onChanged();\n        } else {\n          messageBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public Builder clearMessage() {\n        if (messageBuilder_ == null) {\n          message_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          messageBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public Builder removeMessage(int index) {\n        if (messageBuilder_ == null) {\n          ensureMessageIsMutable();\n          message_.remove(index);\n          onChanged();\n        } else {\n          messageBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Message.Builder getMessageBuilder(\n          int index) {\n        return getMessageFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageOrBuilder getMessageOrBuilder(\n          int index) {\n        if (messageBuilder_ == null) {\n          return message_.get(index);  } else {\n          return messageBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.MessageOrBuilder> \n           getMessageOrBuilderList() {\n        if (messageBuilder_ != null) {\n          return messageBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(message_);\n        }\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Message.Builder addMessageBuilder() {\n        return getMessageFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.Message.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Message.Builder addMessageBuilder(\n          int index) {\n        return getMessageFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.Message.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .Message message = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.Message.Builder> \n           getMessageBuilderList() {\n        return getMessageFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.Message, cn.wildfirechat.proto.WFCMessage.Message.Builder, cn.wildfirechat.proto.WFCMessage.MessageOrBuilder> \n          getMessageFieldBuilder() {\n        if (messageBuilder_ == null) {\n          messageBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.Message, cn.wildfirechat.proto.WFCMessage.Message.Builder, cn.wildfirechat.proto.WFCMessage.MessageOrBuilder>(\n                  message_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          message_ = null;\n        }\n        return messageBuilder_;\n      }\n\n      // required int64 current = 2;\n      private long current_ ;\n      /**\n       * <code>required int64 current = 2;</code>\n       */\n      public boolean hasCurrent() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int64 current = 2;</code>\n       */\n      public long getCurrent() {\n        return current_;\n      }\n      /**\n       * <code>required int64 current = 2;</code>\n       */\n      public Builder setCurrent(long value) {\n        bitField0_ |= 0x00000002;\n        current_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 current = 2;</code>\n       */\n      public Builder clearCurrent() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        current_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // required int64 head = 3;\n      private long head_ ;\n      /**\n       * <code>required int64 head = 3;</code>\n       */\n      public boolean hasHead() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required int64 head = 3;</code>\n       */\n      public long getHead() {\n        return head_;\n      }\n      /**\n       * <code>required int64 head = 3;</code>\n       */\n      public Builder setHead(long value) {\n        bitField0_ |= 0x00000004;\n        head_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 head = 3;</code>\n       */\n      public Builder clearHead() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        head_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:PullMessageResult)\n    }\n\n    static {\n      defaultInstance = new PullMessageResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:PullMessageResult)\n  }\n\n  public interface PullGroupInfoResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .GroupInfo info = 1;\n    /**\n     * <code>repeated .GroupInfo info = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.GroupInfo> \n        getInfoList();\n    /**\n     * <code>repeated .GroupInfo info = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.GroupInfo getInfo(int index);\n    /**\n     * <code>repeated .GroupInfo info = 1;</code>\n     */\n    int getInfoCount();\n    /**\n     * <code>repeated .GroupInfo info = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder> \n        getInfoOrBuilderList();\n    /**\n     * <code>repeated .GroupInfo info = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder getInfoOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code PullGroupInfoResult}\n   */\n  public static final class PullGroupInfoResult extends\n      com.google.protobuf.GeneratedMessage\n      implements PullGroupInfoResultOrBuilder {\n    // Use PullGroupInfoResult.newBuilder() to construct.\n    private PullGroupInfoResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private PullGroupInfoResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final PullGroupInfoResult defaultInstance;\n    public static PullGroupInfoResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public PullGroupInfoResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private PullGroupInfoResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                info_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.GroupInfo>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              info_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.GroupInfo.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          info_ = java.util.Collections.unmodifiableList(info_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupInfoResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupInfoResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult.class, cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<PullGroupInfoResult> PARSER =\n        new com.google.protobuf.AbstractParser<PullGroupInfoResult>() {\n      public PullGroupInfoResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new PullGroupInfoResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<PullGroupInfoResult> getParserForType() {\n      return PARSER;\n    }\n\n    // repeated .GroupInfo info = 1;\n    public static final int INFO_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.GroupInfo> info_;\n    /**\n     * <code>repeated .GroupInfo info = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.GroupInfo> getInfoList() {\n      return info_;\n    }\n    /**\n     * <code>repeated .GroupInfo info = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder> \n        getInfoOrBuilderList() {\n      return info_;\n    }\n    /**\n     * <code>repeated .GroupInfo info = 1;</code>\n     */\n    public int getInfoCount() {\n      return info_.size();\n    }\n    /**\n     * <code>repeated .GroupInfo info = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.GroupInfo getInfo(int index) {\n      return info_.get(index);\n    }\n    /**\n     * <code>repeated .GroupInfo info = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder getInfoOrBuilder(\n        int index) {\n      return info_.get(index);\n    }\n\n    private void initFields() {\n      info_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      for (int i = 0; i < getInfoCount(); i++) {\n        if (!getInfo(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < info_.size(); i++) {\n        output.writeMessage(1, info_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < info_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, info_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code PullGroupInfoResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.PullGroupInfoResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupInfoResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupInfoResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult.class, cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getInfoFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (infoBuilder_ == null) {\n          info_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          infoBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupInfoResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult build() {\n        cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult result = new cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult(this);\n        int from_bitField0_ = bitField0_;\n        if (infoBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            info_ = java.util.Collections.unmodifiableList(info_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.info_ = info_;\n        } else {\n          result.info_ = infoBuilder_.build();\n        }\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult.getDefaultInstance()) return this;\n        if (infoBuilder_ == null) {\n          if (!other.info_.isEmpty()) {\n            if (info_.isEmpty()) {\n              info_ = other.info_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureInfoIsMutable();\n              info_.addAll(other.info_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.info_.isEmpty()) {\n            if (infoBuilder_.isEmpty()) {\n              infoBuilder_.dispose();\n              infoBuilder_ = null;\n              info_ = other.info_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              infoBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getInfoFieldBuilder() : null;\n            } else {\n              infoBuilder_.addAllMessages(other.info_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        for (int i = 0; i < getInfoCount(); i++) {\n          if (!getInfo(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.PullGroupInfoResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .GroupInfo info = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.GroupInfo> info_ =\n        java.util.Collections.emptyList();\n      private void ensureInfoIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          info_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.GroupInfo>(info_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.GroupInfo, cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder, cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder> infoBuilder_;\n\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.GroupInfo> getInfoList() {\n        if (infoBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(info_);\n        } else {\n          return infoBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public int getInfoCount() {\n        if (infoBuilder_ == null) {\n          return info_.size();\n        } else {\n          return infoBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupInfo getInfo(int index) {\n        if (infoBuilder_ == null) {\n          return info_.get(index);\n        } else {\n          return infoBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public Builder setInfo(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupInfo value) {\n        if (infoBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureInfoIsMutable();\n          info_.set(index, value);\n          onChanged();\n        } else {\n          infoBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public Builder setInfo(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder builderForValue) {\n        if (infoBuilder_ == null) {\n          ensureInfoIsMutable();\n          info_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          infoBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public Builder addInfo(cn.wildfirechat.proto.WFCMessage.GroupInfo value) {\n        if (infoBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureInfoIsMutable();\n          info_.add(value);\n          onChanged();\n        } else {\n          infoBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public Builder addInfo(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupInfo value) {\n        if (infoBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureInfoIsMutable();\n          info_.add(index, value);\n          onChanged();\n        } else {\n          infoBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public Builder addInfo(\n          cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder builderForValue) {\n        if (infoBuilder_ == null) {\n          ensureInfoIsMutable();\n          info_.add(builderForValue.build());\n          onChanged();\n        } else {\n          infoBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public Builder addInfo(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder builderForValue) {\n        if (infoBuilder_ == null) {\n          ensureInfoIsMutable();\n          info_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          infoBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public Builder addAllInfo(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.GroupInfo> values) {\n        if (infoBuilder_ == null) {\n          ensureInfoIsMutable();\n          super.addAll(values, info_);\n          onChanged();\n        } else {\n          infoBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public Builder clearInfo() {\n        if (infoBuilder_ == null) {\n          info_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          infoBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public Builder removeInfo(int index) {\n        if (infoBuilder_ == null) {\n          ensureInfoIsMutable();\n          info_.remove(index);\n          onChanged();\n        } else {\n          infoBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder getInfoBuilder(\n          int index) {\n        return getInfoFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder getInfoOrBuilder(\n          int index) {\n        if (infoBuilder_ == null) {\n          return info_.get(index);  } else {\n          return infoBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder> \n           getInfoOrBuilderList() {\n        if (infoBuilder_ != null) {\n          return infoBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(info_);\n        }\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder addInfoBuilder() {\n        return getInfoFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.GroupInfo.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder addInfoBuilder(\n          int index) {\n        return getInfoFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.GroupInfo.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .GroupInfo info = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder> \n           getInfoBuilderList() {\n        return getInfoFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.GroupInfo, cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder, cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder> \n          getInfoFieldBuilder() {\n        if (infoBuilder_ == null) {\n          infoBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.GroupInfo, cn.wildfirechat.proto.WFCMessage.GroupInfo.Builder, cn.wildfirechat.proto.WFCMessage.GroupInfoOrBuilder>(\n                  info_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          info_ = null;\n        }\n        return infoBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:PullGroupInfoResult)\n    }\n\n    static {\n      defaultInstance = new PullGroupInfoResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:PullGroupInfoResult)\n  }\n\n  public interface PullGroupMemberRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string target = 1;\n    /**\n     * <code>required string target = 1;</code>\n     */\n    boolean hasTarget();\n    /**\n     * <code>required string target = 1;</code>\n     */\n    java.lang.String getTarget();\n    /**\n     * <code>required string target = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getTargetBytes();\n\n    // required int64 head = 2;\n    /**\n     * <code>required int64 head = 2;</code>\n     */\n    boolean hasHead();\n    /**\n     * <code>required int64 head = 2;</code>\n     */\n    long getHead();\n  }\n  /**\n   * Protobuf type {@code PullGroupMemberRequest}\n   */\n  public static final class PullGroupMemberRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements PullGroupMemberRequestOrBuilder {\n    // Use PullGroupMemberRequest.newBuilder() to construct.\n    private PullGroupMemberRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private PullGroupMemberRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final PullGroupMemberRequest defaultInstance;\n    public static PullGroupMemberRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public PullGroupMemberRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private PullGroupMemberRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              target_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              head_ = input.readInt64();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupMemberRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupMemberRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest.class, cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<PullGroupMemberRequest> PARSER =\n        new com.google.protobuf.AbstractParser<PullGroupMemberRequest>() {\n      public PullGroupMemberRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new PullGroupMemberRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<PullGroupMemberRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string target = 1;\n    public static final int TARGET_FIELD_NUMBER = 1;\n    private java.lang.Object target_;\n    /**\n     * <code>required string target = 1;</code>\n     */\n    public boolean hasTarget() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string target = 1;</code>\n     */\n    public java.lang.String getTarget() {\n      java.lang.Object ref = target_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          target_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string target = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTargetBytes() {\n      java.lang.Object ref = target_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        target_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int64 head = 2;\n    public static final int HEAD_FIELD_NUMBER = 2;\n    private long head_;\n    /**\n     * <code>required int64 head = 2;</code>\n     */\n    public boolean hasHead() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int64 head = 2;</code>\n     */\n    public long getHead() {\n      return head_;\n    }\n\n    private void initFields() {\n      target_ = \"\";\n      head_ = 0L;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasTarget()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasHead()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getTargetBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt64(2, head_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getTargetBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(2, head_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code PullGroupMemberRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupMemberRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupMemberRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest.class, cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        target_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        head_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupMemberRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest build() {\n        cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest result = new cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.target_ = target_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.head_ = head_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest.getDefaultInstance()) return this;\n        if (other.hasTarget()) {\n          bitField0_ |= 0x00000001;\n          target_ = other.target_;\n          onChanged();\n        }\n        if (other.hasHead()) {\n          setHead(other.getHead());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasTarget()) {\n          \n          return false;\n        }\n        if (!hasHead()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.PullGroupMemberRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string target = 1;\n      private java.lang.Object target_ = \"\";\n      /**\n       * <code>required string target = 1;</code>\n       */\n      public boolean hasTarget() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string target = 1;</code>\n       */\n      public java.lang.String getTarget() {\n        java.lang.Object ref = target_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          target_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string target = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTargetBytes() {\n        java.lang.Object ref = target_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          target_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string target = 1;</code>\n       */\n      public Builder setTarget(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        target_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string target = 1;</code>\n       */\n      public Builder clearTarget() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        target_ = getDefaultInstance().getTarget();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string target = 1;</code>\n       */\n      public Builder setTargetBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        target_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int64 head = 2;\n      private long head_ ;\n      /**\n       * <code>required int64 head = 2;</code>\n       */\n      public boolean hasHead() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int64 head = 2;</code>\n       */\n      public long getHead() {\n        return head_;\n      }\n      /**\n       * <code>required int64 head = 2;</code>\n       */\n      public Builder setHead(long value) {\n        bitField0_ |= 0x00000002;\n        head_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 head = 2;</code>\n       */\n      public Builder clearHead() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        head_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:PullGroupMemberRequest)\n    }\n\n    static {\n      defaultInstance = new PullGroupMemberRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:PullGroupMemberRequest)\n  }\n\n  public interface PullGroupMemberResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .GroupMember member = 1;\n    /**\n     * <code>repeated .GroupMember member = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> \n        getMemberList();\n    /**\n     * <code>repeated .GroupMember member = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.GroupMember getMember(int index);\n    /**\n     * <code>repeated .GroupMember member = 1;</code>\n     */\n    int getMemberCount();\n    /**\n     * <code>repeated .GroupMember member = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> \n        getMemberOrBuilderList();\n    /**\n     * <code>repeated .GroupMember member = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder getMemberOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code PullGroupMemberResult}\n   */\n  public static final class PullGroupMemberResult extends\n      com.google.protobuf.GeneratedMessage\n      implements PullGroupMemberResultOrBuilder {\n    // Use PullGroupMemberResult.newBuilder() to construct.\n    private PullGroupMemberResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private PullGroupMemberResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final PullGroupMemberResult defaultInstance;\n    public static PullGroupMemberResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public PullGroupMemberResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private PullGroupMemberResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                member_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.GroupMember>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              member_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.GroupMember.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          member_ = java.util.Collections.unmodifiableList(member_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupMemberResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupMemberResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult.class, cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<PullGroupMemberResult> PARSER =\n        new com.google.protobuf.AbstractParser<PullGroupMemberResult>() {\n      public PullGroupMemberResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new PullGroupMemberResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<PullGroupMemberResult> getParserForType() {\n      return PARSER;\n    }\n\n    // repeated .GroupMember member = 1;\n    public static final int MEMBER_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> member_;\n    /**\n     * <code>repeated .GroupMember member = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> getMemberList() {\n      return member_;\n    }\n    /**\n     * <code>repeated .GroupMember member = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> \n        getMemberOrBuilderList() {\n      return member_;\n    }\n    /**\n     * <code>repeated .GroupMember member = 1;</code>\n     */\n    public int getMemberCount() {\n      return member_.size();\n    }\n    /**\n     * <code>repeated .GroupMember member = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.GroupMember getMember(int index) {\n      return member_.get(index);\n    }\n    /**\n     * <code>repeated .GroupMember member = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder getMemberOrBuilder(\n        int index) {\n      return member_.get(index);\n    }\n\n    private void initFields() {\n      member_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      for (int i = 0; i < getMemberCount(); i++) {\n        if (!getMember(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < member_.size(); i++) {\n        output.writeMessage(1, member_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < member_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, member_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code PullGroupMemberResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.PullGroupMemberResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupMemberResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupMemberResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult.class, cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getMemberFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (memberBuilder_ == null) {\n          member_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          memberBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullGroupMemberResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult build() {\n        cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult result = new cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult(this);\n        int from_bitField0_ = bitField0_;\n        if (memberBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            member_ = java.util.Collections.unmodifiableList(member_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.member_ = member_;\n        } else {\n          result.member_ = memberBuilder_.build();\n        }\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult.getDefaultInstance()) return this;\n        if (memberBuilder_ == null) {\n          if (!other.member_.isEmpty()) {\n            if (member_.isEmpty()) {\n              member_ = other.member_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureMemberIsMutable();\n              member_.addAll(other.member_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.member_.isEmpty()) {\n            if (memberBuilder_.isEmpty()) {\n              memberBuilder_.dispose();\n              memberBuilder_ = null;\n              member_ = other.member_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              memberBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getMemberFieldBuilder() : null;\n            } else {\n              memberBuilder_.addAllMessages(other.member_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        for (int i = 0; i < getMemberCount(); i++) {\n          if (!getMember(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.PullGroupMemberResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .GroupMember member = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> member_ =\n        java.util.Collections.emptyList();\n      private void ensureMemberIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          member_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.GroupMember>(member_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.GroupMember, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder, cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> memberBuilder_;\n\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember> getMemberList() {\n        if (memberBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(member_);\n        } else {\n          return memberBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public int getMemberCount() {\n        if (memberBuilder_ == null) {\n          return member_.size();\n        } else {\n          return memberBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMember getMember(int index) {\n        if (memberBuilder_ == null) {\n          return member_.get(index);\n        } else {\n          return memberBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public Builder setMember(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupMember value) {\n        if (memberBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMemberIsMutable();\n          member_.set(index, value);\n          onChanged();\n        } else {\n          memberBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public Builder setMember(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder builderForValue) {\n        if (memberBuilder_ == null) {\n          ensureMemberIsMutable();\n          member_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          memberBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public Builder addMember(cn.wildfirechat.proto.WFCMessage.GroupMember value) {\n        if (memberBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMemberIsMutable();\n          member_.add(value);\n          onChanged();\n        } else {\n          memberBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public Builder addMember(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupMember value) {\n        if (memberBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureMemberIsMutable();\n          member_.add(index, value);\n          onChanged();\n        } else {\n          memberBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public Builder addMember(\n          cn.wildfirechat.proto.WFCMessage.GroupMember.Builder builderForValue) {\n        if (memberBuilder_ == null) {\n          ensureMemberIsMutable();\n          member_.add(builderForValue.build());\n          onChanged();\n        } else {\n          memberBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public Builder addMember(\n          int index, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder builderForValue) {\n        if (memberBuilder_ == null) {\n          ensureMemberIsMutable();\n          member_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          memberBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public Builder addAllMember(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.GroupMember> values) {\n        if (memberBuilder_ == null) {\n          ensureMemberIsMutable();\n          super.addAll(values, member_);\n          onChanged();\n        } else {\n          memberBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public Builder clearMember() {\n        if (memberBuilder_ == null) {\n          member_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          memberBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public Builder removeMember(int index) {\n        if (memberBuilder_ == null) {\n          ensureMemberIsMutable();\n          member_.remove(index);\n          onChanged();\n        } else {\n          memberBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMember.Builder getMemberBuilder(\n          int index) {\n        return getMemberFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder getMemberOrBuilder(\n          int index) {\n        if (memberBuilder_ == null) {\n          return member_.get(index);  } else {\n          return memberBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> \n           getMemberOrBuilderList() {\n        if (memberBuilder_ != null) {\n          return memberBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(member_);\n        }\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMember.Builder addMemberBuilder() {\n        return getMemberFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.GroupMember.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.GroupMember.Builder addMemberBuilder(\n          int index) {\n        return getMemberFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.GroupMember.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .GroupMember member = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.GroupMember.Builder> \n           getMemberBuilderList() {\n        return getMemberFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.GroupMember, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder, cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder> \n          getMemberFieldBuilder() {\n        if (memberBuilder_ == null) {\n          memberBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.GroupMember, cn.wildfirechat.proto.WFCMessage.GroupMember.Builder, cn.wildfirechat.proto.WFCMessage.GroupMemberOrBuilder>(\n                  member_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          member_ = null;\n        }\n        return memberBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:PullGroupMemberResult)\n    }\n\n    static {\n      defaultInstance = new PullGroupMemberResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:PullGroupMemberResult)\n  }\n\n  public interface UserRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string uid = 1;\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    boolean hasUid();\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    java.lang.String getUid();\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getUidBytes();\n\n    // optional int64 update_dt = 2;\n    /**\n     * <code>optional int64 update_dt = 2;</code>\n     */\n    boolean hasUpdateDt();\n    /**\n     * <code>optional int64 update_dt = 2;</code>\n     */\n    long getUpdateDt();\n  }\n  /**\n   * Protobuf type {@code UserRequest}\n   */\n  public static final class UserRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements UserRequestOrBuilder {\n    // Use UserRequest.newBuilder() to construct.\n    private UserRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private UserRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final UserRequest defaultInstance;\n    public static UserRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public UserRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private UserRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              uid_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              updateDt_ = input.readInt64();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_UserRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_UserRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.UserRequest.class, cn.wildfirechat.proto.WFCMessage.UserRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<UserRequest> PARSER =\n        new com.google.protobuf.AbstractParser<UserRequest>() {\n      public UserRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new UserRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<UserRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string uid = 1;\n    public static final int UID_FIELD_NUMBER = 1;\n    private java.lang.Object uid_;\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public boolean hasUid() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public java.lang.String getUid() {\n      java.lang.Object ref = uid_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          uid_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getUidBytes() {\n      java.lang.Object ref = uid_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        uid_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int64 update_dt = 2;\n    public static final int UPDATE_DT_FIELD_NUMBER = 2;\n    private long updateDt_;\n    /**\n     * <code>optional int64 update_dt = 2;</code>\n     */\n    public boolean hasUpdateDt() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional int64 update_dt = 2;</code>\n     */\n    public long getUpdateDt() {\n      return updateDt_;\n    }\n\n    private void initFields() {\n      uid_ = \"\";\n      updateDt_ = 0L;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasUid()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt64(2, updateDt_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(2, updateDt_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.UserRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.UserRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code UserRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.UserRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_UserRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_UserRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.UserRequest.class, cn.wildfirechat.proto.WFCMessage.UserRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.UserRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        uid_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        updateDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_UserRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.UserRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.UserRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.UserRequest build() {\n        cn.wildfirechat.proto.WFCMessage.UserRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.UserRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.UserRequest result = new cn.wildfirechat.proto.WFCMessage.UserRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.uid_ = uid_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.updateDt_ = updateDt_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.UserRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.UserRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.UserRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.UserRequest.getDefaultInstance()) return this;\n        if (other.hasUid()) {\n          bitField0_ |= 0x00000001;\n          uid_ = other.uid_;\n          onChanged();\n        }\n        if (other.hasUpdateDt()) {\n          setUpdateDt(other.getUpdateDt());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasUid()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.UserRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.UserRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string uid = 1;\n      private java.lang.Object uid_ = \"\";\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public boolean hasUid() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public java.lang.String getUid() {\n        java.lang.Object ref = uid_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          uid_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getUidBytes() {\n        java.lang.Object ref = uid_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          uid_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder setUid(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        uid_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder clearUid() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        uid_ = getDefaultInstance().getUid();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder setUidBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        uid_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 update_dt = 2;\n      private long updateDt_ ;\n      /**\n       * <code>optional int64 update_dt = 2;</code>\n       */\n      public boolean hasUpdateDt() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional int64 update_dt = 2;</code>\n       */\n      public long getUpdateDt() {\n        return updateDt_;\n      }\n      /**\n       * <code>optional int64 update_dt = 2;</code>\n       */\n      public Builder setUpdateDt(long value) {\n        bitField0_ |= 0x00000002;\n        updateDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 update_dt = 2;</code>\n       */\n      public Builder clearUpdateDt() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        updateDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:UserRequest)\n    }\n\n    static {\n      defaultInstance = new UserRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:UserRequest)\n  }\n\n  public interface PullUserRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .UserRequest request = 1;\n    /**\n     * <code>repeated .UserRequest request = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.UserRequest> \n        getRequestList();\n    /**\n     * <code>repeated .UserRequest request = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.UserRequest getRequest(int index);\n    /**\n     * <code>repeated .UserRequest request = 1;</code>\n     */\n    int getRequestCount();\n    /**\n     * <code>repeated .UserRequest request = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.UserRequestOrBuilder> \n        getRequestOrBuilderList();\n    /**\n     * <code>repeated .UserRequest request = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.UserRequestOrBuilder getRequestOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code PullUserRequest}\n   */\n  public static final class PullUserRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements PullUserRequestOrBuilder {\n    // Use PullUserRequest.newBuilder() to construct.\n    private PullUserRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private PullUserRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final PullUserRequest defaultInstance;\n    public static PullUserRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public PullUserRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private PullUserRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                request_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.UserRequest>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              request_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.UserRequest.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          request_ = java.util.Collections.unmodifiableList(request_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullUserRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullUserRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.PullUserRequest.class, cn.wildfirechat.proto.WFCMessage.PullUserRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<PullUserRequest> PARSER =\n        new com.google.protobuf.AbstractParser<PullUserRequest>() {\n      public PullUserRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new PullUserRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<PullUserRequest> getParserForType() {\n      return PARSER;\n    }\n\n    // repeated .UserRequest request = 1;\n    public static final int REQUEST_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.UserRequest> request_;\n    /**\n     * <code>repeated .UserRequest request = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.UserRequest> getRequestList() {\n      return request_;\n    }\n    /**\n     * <code>repeated .UserRequest request = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.UserRequestOrBuilder> \n        getRequestOrBuilderList() {\n      return request_;\n    }\n    /**\n     * <code>repeated .UserRequest request = 1;</code>\n     */\n    public int getRequestCount() {\n      return request_.size();\n    }\n    /**\n     * <code>repeated .UserRequest request = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.UserRequest getRequest(int index) {\n      return request_.get(index);\n    }\n    /**\n     * <code>repeated .UserRequest request = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.UserRequestOrBuilder getRequestOrBuilder(\n        int index) {\n      return request_.get(index);\n    }\n\n    private void initFields() {\n      request_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      for (int i = 0; i < getRequestCount(); i++) {\n        if (!getRequest(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < request_.size(); i++) {\n        output.writeMessage(1, request_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < request_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, request_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.PullUserRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.PullUserRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code PullUserRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.PullUserRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullUserRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullUserRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.PullUserRequest.class, cn.wildfirechat.proto.WFCMessage.PullUserRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.PullUserRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getRequestFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (requestBuilder_ == null) {\n          request_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          requestBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullUserRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullUserRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.PullUserRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullUserRequest build() {\n        cn.wildfirechat.proto.WFCMessage.PullUserRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullUserRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.PullUserRequest result = new cn.wildfirechat.proto.WFCMessage.PullUserRequest(this);\n        int from_bitField0_ = bitField0_;\n        if (requestBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            request_ = java.util.Collections.unmodifiableList(request_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.request_ = request_;\n        } else {\n          result.request_ = requestBuilder_.build();\n        }\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.PullUserRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.PullUserRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.PullUserRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.PullUserRequest.getDefaultInstance()) return this;\n        if (requestBuilder_ == null) {\n          if (!other.request_.isEmpty()) {\n            if (request_.isEmpty()) {\n              request_ = other.request_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureRequestIsMutable();\n              request_.addAll(other.request_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.request_.isEmpty()) {\n            if (requestBuilder_.isEmpty()) {\n              requestBuilder_.dispose();\n              requestBuilder_ = null;\n              request_ = other.request_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              requestBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getRequestFieldBuilder() : null;\n            } else {\n              requestBuilder_.addAllMessages(other.request_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        for (int i = 0; i < getRequestCount(); i++) {\n          if (!getRequest(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.PullUserRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.PullUserRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .UserRequest request = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.UserRequest> request_ =\n        java.util.Collections.emptyList();\n      private void ensureRequestIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          request_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.UserRequest>(request_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.UserRequest, cn.wildfirechat.proto.WFCMessage.UserRequest.Builder, cn.wildfirechat.proto.WFCMessage.UserRequestOrBuilder> requestBuilder_;\n\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.UserRequest> getRequestList() {\n        if (requestBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(request_);\n        } else {\n          return requestBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public int getRequestCount() {\n        if (requestBuilder_ == null) {\n          return request_.size();\n        } else {\n          return requestBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserRequest getRequest(int index) {\n        if (requestBuilder_ == null) {\n          return request_.get(index);\n        } else {\n          return requestBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public Builder setRequest(\n          int index, cn.wildfirechat.proto.WFCMessage.UserRequest value) {\n        if (requestBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureRequestIsMutable();\n          request_.set(index, value);\n          onChanged();\n        } else {\n          requestBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public Builder setRequest(\n          int index, cn.wildfirechat.proto.WFCMessage.UserRequest.Builder builderForValue) {\n        if (requestBuilder_ == null) {\n          ensureRequestIsMutable();\n          request_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          requestBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public Builder addRequest(cn.wildfirechat.proto.WFCMessage.UserRequest value) {\n        if (requestBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureRequestIsMutable();\n          request_.add(value);\n          onChanged();\n        } else {\n          requestBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public Builder addRequest(\n          int index, cn.wildfirechat.proto.WFCMessage.UserRequest value) {\n        if (requestBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureRequestIsMutable();\n          request_.add(index, value);\n          onChanged();\n        } else {\n          requestBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public Builder addRequest(\n          cn.wildfirechat.proto.WFCMessage.UserRequest.Builder builderForValue) {\n        if (requestBuilder_ == null) {\n          ensureRequestIsMutable();\n          request_.add(builderForValue.build());\n          onChanged();\n        } else {\n          requestBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public Builder addRequest(\n          int index, cn.wildfirechat.proto.WFCMessage.UserRequest.Builder builderForValue) {\n        if (requestBuilder_ == null) {\n          ensureRequestIsMutable();\n          request_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          requestBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public Builder addAllRequest(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.UserRequest> values) {\n        if (requestBuilder_ == null) {\n          ensureRequestIsMutable();\n          super.addAll(values, request_);\n          onChanged();\n        } else {\n          requestBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public Builder clearRequest() {\n        if (requestBuilder_ == null) {\n          request_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          requestBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public Builder removeRequest(int index) {\n        if (requestBuilder_ == null) {\n          ensureRequestIsMutable();\n          request_.remove(index);\n          onChanged();\n        } else {\n          requestBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserRequest.Builder getRequestBuilder(\n          int index) {\n        return getRequestFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserRequestOrBuilder getRequestOrBuilder(\n          int index) {\n        if (requestBuilder_ == null) {\n          return request_.get(index);  } else {\n          return requestBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.UserRequestOrBuilder> \n           getRequestOrBuilderList() {\n        if (requestBuilder_ != null) {\n          return requestBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(request_);\n        }\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserRequest.Builder addRequestBuilder() {\n        return getRequestFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.UserRequest.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserRequest.Builder addRequestBuilder(\n          int index) {\n        return getRequestFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.UserRequest.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .UserRequest request = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.UserRequest.Builder> \n           getRequestBuilderList() {\n        return getRequestFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.UserRequest, cn.wildfirechat.proto.WFCMessage.UserRequest.Builder, cn.wildfirechat.proto.WFCMessage.UserRequestOrBuilder> \n          getRequestFieldBuilder() {\n        if (requestBuilder_ == null) {\n          requestBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.UserRequest, cn.wildfirechat.proto.WFCMessage.UserRequest.Builder, cn.wildfirechat.proto.WFCMessage.UserRequestOrBuilder>(\n                  request_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          request_ = null;\n        }\n        return requestBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:PullUserRequest)\n    }\n\n    static {\n      defaultInstance = new PullUserRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:PullUserRequest)\n  }\n\n  public interface UserResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required .User user = 1;\n    /**\n     * <code>required .User user = 1;</code>\n     */\n    boolean hasUser();\n    /**\n     * <code>required .User user = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.User getUser();\n    /**\n     * <code>required .User user = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.UserOrBuilder getUserOrBuilder();\n\n    // required int32 code = 2;\n    /**\n     * <code>required int32 code = 2;</code>\n     */\n    boolean hasCode();\n    /**\n     * <code>required int32 code = 2;</code>\n     */\n    int getCode();\n  }\n  /**\n   * Protobuf type {@code UserResult}\n   */\n  public static final class UserResult extends\n      com.google.protobuf.GeneratedMessage\n      implements UserResultOrBuilder {\n    // Use UserResult.newBuilder() to construct.\n    private UserResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private UserResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final UserResult defaultInstance;\n    public static UserResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public UserResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private UserResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              cn.wildfirechat.proto.WFCMessage.User.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                subBuilder = user_.toBuilder();\n              }\n              user_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.User.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(user_);\n                user_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000001;\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              code_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_UserResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_UserResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.UserResult.class, cn.wildfirechat.proto.WFCMessage.UserResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<UserResult> PARSER =\n        new com.google.protobuf.AbstractParser<UserResult>() {\n      public UserResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new UserResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<UserResult> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required .User user = 1;\n    public static final int USER_FIELD_NUMBER = 1;\n    private cn.wildfirechat.proto.WFCMessage.User user_;\n    /**\n     * <code>required .User user = 1;</code>\n     */\n    public boolean hasUser() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required .User user = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.User getUser() {\n      return user_;\n    }\n    /**\n     * <code>required .User user = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.UserOrBuilder getUserOrBuilder() {\n      return user_;\n    }\n\n    // required int32 code = 2;\n    public static final int CODE_FIELD_NUMBER = 2;\n    private int code_;\n    /**\n     * <code>required int32 code = 2;</code>\n     */\n    public boolean hasCode() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 code = 2;</code>\n     */\n    public int getCode() {\n      return code_;\n    }\n\n    private void initFields() {\n      user_ = cn.wildfirechat.proto.WFCMessage.User.getDefaultInstance();\n      code_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasUser()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasCode()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!getUser().isInitialized()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeMessage(1, user_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, code_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, user_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, code_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.UserResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.UserResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code UserResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.UserResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_UserResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_UserResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.UserResult.class, cn.wildfirechat.proto.WFCMessage.UserResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.UserResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getUserFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (userBuilder_ == null) {\n          user_ = cn.wildfirechat.proto.WFCMessage.User.getDefaultInstance();\n        } else {\n          userBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000001);\n        code_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_UserResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.UserResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.UserResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.UserResult build() {\n        cn.wildfirechat.proto.WFCMessage.UserResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.UserResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.UserResult result = new cn.wildfirechat.proto.WFCMessage.UserResult(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        if (userBuilder_ == null) {\n          result.user_ = user_;\n        } else {\n          result.user_ = userBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.code_ = code_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.UserResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.UserResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.UserResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.UserResult.getDefaultInstance()) return this;\n        if (other.hasUser()) {\n          mergeUser(other.getUser());\n        }\n        if (other.hasCode()) {\n          setCode(other.getCode());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasUser()) {\n          \n          return false;\n        }\n        if (!hasCode()) {\n          \n          return false;\n        }\n        if (!getUser().isInitialized()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.UserResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.UserResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required .User user = 1;\n      private cn.wildfirechat.proto.WFCMessage.User user_ = cn.wildfirechat.proto.WFCMessage.User.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.User, cn.wildfirechat.proto.WFCMessage.User.Builder, cn.wildfirechat.proto.WFCMessage.UserOrBuilder> userBuilder_;\n      /**\n       * <code>required .User user = 1;</code>\n       */\n      public boolean hasUser() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required .User user = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.User getUser() {\n        if (userBuilder_ == null) {\n          return user_;\n        } else {\n          return userBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>required .User user = 1;</code>\n       */\n      public Builder setUser(cn.wildfirechat.proto.WFCMessage.User value) {\n        if (userBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          user_ = value;\n          onChanged();\n        } else {\n          userBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .User user = 1;</code>\n       */\n      public Builder setUser(\n          cn.wildfirechat.proto.WFCMessage.User.Builder builderForValue) {\n        if (userBuilder_ == null) {\n          user_ = builderForValue.build();\n          onChanged();\n        } else {\n          userBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .User user = 1;</code>\n       */\n      public Builder mergeUser(cn.wildfirechat.proto.WFCMessage.User value) {\n        if (userBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001) &&\n              user_ != cn.wildfirechat.proto.WFCMessage.User.getDefaultInstance()) {\n            user_ =\n              cn.wildfirechat.proto.WFCMessage.User.newBuilder(user_).mergeFrom(value).buildPartial();\n          } else {\n            user_ = value;\n          }\n          onChanged();\n        } else {\n          userBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .User user = 1;</code>\n       */\n      public Builder clearUser() {\n        if (userBuilder_ == null) {\n          user_ = cn.wildfirechat.proto.WFCMessage.User.getDefaultInstance();\n          onChanged();\n        } else {\n          userBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000001);\n        return this;\n      }\n      /**\n       * <code>required .User user = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.User.Builder getUserBuilder() {\n        bitField0_ |= 0x00000001;\n        onChanged();\n        return getUserFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>required .User user = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserOrBuilder getUserOrBuilder() {\n        if (userBuilder_ != null) {\n          return userBuilder_.getMessageOrBuilder();\n        } else {\n          return user_;\n        }\n      }\n      /**\n       * <code>required .User user = 1;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.User, cn.wildfirechat.proto.WFCMessage.User.Builder, cn.wildfirechat.proto.WFCMessage.UserOrBuilder> \n          getUserFieldBuilder() {\n        if (userBuilder_ == null) {\n          userBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.User, cn.wildfirechat.proto.WFCMessage.User.Builder, cn.wildfirechat.proto.WFCMessage.UserOrBuilder>(\n                  user_,\n                  getParentForChildren(),\n                  isClean());\n          user_ = null;\n        }\n        return userBuilder_;\n      }\n\n      // required int32 code = 2;\n      private int code_ ;\n      /**\n       * <code>required int32 code = 2;</code>\n       */\n      public boolean hasCode() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 code = 2;</code>\n       */\n      public int getCode() {\n        return code_;\n      }\n      /**\n       * <code>required int32 code = 2;</code>\n       */\n      public Builder setCode(int value) {\n        bitField0_ |= 0x00000002;\n        code_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 code = 2;</code>\n       */\n      public Builder clearCode() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        code_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:UserResult)\n    }\n\n    static {\n      defaultInstance = new UserResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:UserResult)\n  }\n\n  public interface PullUserResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .UserResult result = 1;\n    /**\n     * <code>repeated .UserResult result = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.UserResult> \n        getResultList();\n    /**\n     * <code>repeated .UserResult result = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.UserResult getResult(int index);\n    /**\n     * <code>repeated .UserResult result = 1;</code>\n     */\n    int getResultCount();\n    /**\n     * <code>repeated .UserResult result = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.UserResultOrBuilder> \n        getResultOrBuilderList();\n    /**\n     * <code>repeated .UserResult result = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.UserResultOrBuilder getResultOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code PullUserResult}\n   */\n  public static final class PullUserResult extends\n      com.google.protobuf.GeneratedMessage\n      implements PullUserResultOrBuilder {\n    // Use PullUserResult.newBuilder() to construct.\n    private PullUserResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private PullUserResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final PullUserResult defaultInstance;\n    public static PullUserResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public PullUserResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private PullUserResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                result_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.UserResult>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              result_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.UserResult.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          result_ = java.util.Collections.unmodifiableList(result_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullUserResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_PullUserResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.PullUserResult.class, cn.wildfirechat.proto.WFCMessage.PullUserResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<PullUserResult> PARSER =\n        new com.google.protobuf.AbstractParser<PullUserResult>() {\n      public PullUserResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new PullUserResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<PullUserResult> getParserForType() {\n      return PARSER;\n    }\n\n    // repeated .UserResult result = 1;\n    public static final int RESULT_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.UserResult> result_;\n    /**\n     * <code>repeated .UserResult result = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.UserResult> getResultList() {\n      return result_;\n    }\n    /**\n     * <code>repeated .UserResult result = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.UserResultOrBuilder> \n        getResultOrBuilderList() {\n      return result_;\n    }\n    /**\n     * <code>repeated .UserResult result = 1;</code>\n     */\n    public int getResultCount() {\n      return result_.size();\n    }\n    /**\n     * <code>repeated .UserResult result = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.UserResult getResult(int index) {\n      return result_.get(index);\n    }\n    /**\n     * <code>repeated .UserResult result = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.UserResultOrBuilder getResultOrBuilder(\n        int index) {\n      return result_.get(index);\n    }\n\n    private void initFields() {\n      result_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      for (int i = 0; i < getResultCount(); i++) {\n        if (!getResult(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < result_.size(); i++) {\n        output.writeMessage(1, result_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < result_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, result_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.PullUserResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.PullUserResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.PullUserResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code PullUserResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.PullUserResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullUserResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullUserResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.PullUserResult.class, cn.wildfirechat.proto.WFCMessage.PullUserResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.PullUserResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getResultFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (resultBuilder_ == null) {\n          result_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          resultBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_PullUserResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullUserResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.PullUserResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullUserResult build() {\n        cn.wildfirechat.proto.WFCMessage.PullUserResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.PullUserResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.PullUserResult result = new cn.wildfirechat.proto.WFCMessage.PullUserResult(this);\n        int from_bitField0_ = bitField0_;\n        if (resultBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            result_ = java.util.Collections.unmodifiableList(result_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.result_ = result_;\n        } else {\n          result.result_ = resultBuilder_.build();\n        }\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.PullUserResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.PullUserResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.PullUserResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.PullUserResult.getDefaultInstance()) return this;\n        if (resultBuilder_ == null) {\n          if (!other.result_.isEmpty()) {\n            if (result_.isEmpty()) {\n              result_ = other.result_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureResultIsMutable();\n              result_.addAll(other.result_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.result_.isEmpty()) {\n            if (resultBuilder_.isEmpty()) {\n              resultBuilder_.dispose();\n              resultBuilder_ = null;\n              result_ = other.result_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              resultBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getResultFieldBuilder() : null;\n            } else {\n              resultBuilder_.addAllMessages(other.result_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        for (int i = 0; i < getResultCount(); i++) {\n          if (!getResult(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.PullUserResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.PullUserResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .UserResult result = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.UserResult> result_ =\n        java.util.Collections.emptyList();\n      private void ensureResultIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          result_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.UserResult>(result_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.UserResult, cn.wildfirechat.proto.WFCMessage.UserResult.Builder, cn.wildfirechat.proto.WFCMessage.UserResultOrBuilder> resultBuilder_;\n\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.UserResult> getResultList() {\n        if (resultBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(result_);\n        } else {\n          return resultBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public int getResultCount() {\n        if (resultBuilder_ == null) {\n          return result_.size();\n        } else {\n          return resultBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserResult getResult(int index) {\n        if (resultBuilder_ == null) {\n          return result_.get(index);\n        } else {\n          return resultBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public Builder setResult(\n          int index, cn.wildfirechat.proto.WFCMessage.UserResult value) {\n        if (resultBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureResultIsMutable();\n          result_.set(index, value);\n          onChanged();\n        } else {\n          resultBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public Builder setResult(\n          int index, cn.wildfirechat.proto.WFCMessage.UserResult.Builder builderForValue) {\n        if (resultBuilder_ == null) {\n          ensureResultIsMutable();\n          result_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          resultBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public Builder addResult(cn.wildfirechat.proto.WFCMessage.UserResult value) {\n        if (resultBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureResultIsMutable();\n          result_.add(value);\n          onChanged();\n        } else {\n          resultBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public Builder addResult(\n          int index, cn.wildfirechat.proto.WFCMessage.UserResult value) {\n        if (resultBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureResultIsMutable();\n          result_.add(index, value);\n          onChanged();\n        } else {\n          resultBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public Builder addResult(\n          cn.wildfirechat.proto.WFCMessage.UserResult.Builder builderForValue) {\n        if (resultBuilder_ == null) {\n          ensureResultIsMutable();\n          result_.add(builderForValue.build());\n          onChanged();\n        } else {\n          resultBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public Builder addResult(\n          int index, cn.wildfirechat.proto.WFCMessage.UserResult.Builder builderForValue) {\n        if (resultBuilder_ == null) {\n          ensureResultIsMutable();\n          result_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          resultBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public Builder addAllResult(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.UserResult> values) {\n        if (resultBuilder_ == null) {\n          ensureResultIsMutable();\n          super.addAll(values, result_);\n          onChanged();\n        } else {\n          resultBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public Builder clearResult() {\n        if (resultBuilder_ == null) {\n          result_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          resultBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public Builder removeResult(int index) {\n        if (resultBuilder_ == null) {\n          ensureResultIsMutable();\n          result_.remove(index);\n          onChanged();\n        } else {\n          resultBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserResult.Builder getResultBuilder(\n          int index) {\n        return getResultFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserResultOrBuilder getResultOrBuilder(\n          int index) {\n        if (resultBuilder_ == null) {\n          return result_.get(index);  } else {\n          return resultBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.UserResultOrBuilder> \n           getResultOrBuilderList() {\n        if (resultBuilder_ != null) {\n          return resultBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(result_);\n        }\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserResult.Builder addResultBuilder() {\n        return getResultFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.UserResult.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserResult.Builder addResultBuilder(\n          int index) {\n        return getResultFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.UserResult.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .UserResult result = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.UserResult.Builder> \n           getResultBuilderList() {\n        return getResultFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.UserResult, cn.wildfirechat.proto.WFCMessage.UserResult.Builder, cn.wildfirechat.proto.WFCMessage.UserResultOrBuilder> \n          getResultFieldBuilder() {\n        if (resultBuilder_ == null) {\n          resultBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.UserResult, cn.wildfirechat.proto.WFCMessage.UserResult.Builder, cn.wildfirechat.proto.WFCMessage.UserResultOrBuilder>(\n                  result_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          result_ = null;\n        }\n        return resultBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:PullUserResult)\n    }\n\n    static {\n      defaultInstance = new PullUserResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:PullUserResult)\n  }\n\n  public interface QuitGroupRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string group_id = 1;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    boolean hasGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    java.lang.String getGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getGroupIdBytes();\n\n    // repeated int32 to_line = 2;\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    java.util.List<java.lang.Integer> getToLineList();\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    int getToLineCount();\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    int getToLine(int index);\n\n    // optional .MessageContent notify_content = 3;\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    boolean hasNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder();\n\n    // optional int32 keep_msg = 4;\n    /**\n     * <code>optional int32 keep_msg = 4;</code>\n     */\n    boolean hasKeepMsg();\n    /**\n     * <code>optional int32 keep_msg = 4;</code>\n     */\n    int getKeepMsg();\n  }\n  /**\n   * Protobuf type {@code QuitGroupRequest}\n   */\n  public static final class QuitGroupRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements QuitGroupRequestOrBuilder {\n    // Use QuitGroupRequest.newBuilder() to construct.\n    private QuitGroupRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private QuitGroupRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final QuitGroupRequest defaultInstance;\n    public static QuitGroupRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public QuitGroupRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private QuitGroupRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              groupId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              toLine_.add(input.readInt32());\n              break;\n            }\n            case 18: {\n              int length = input.readRawVarint32();\n              int limit = input.pushLimit(length);\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002) && input.getBytesUntilLimit() > 0) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              while (input.getBytesUntilLimit() > 0) {\n                toLine_.add(input.readInt32());\n              }\n              input.popLimit(limit);\n              break;\n            }\n            case 26: {\n              cn.wildfirechat.proto.WFCMessage.MessageContent.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                subBuilder = notifyContent_.toBuilder();\n              }\n              notifyContent_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.MessageContent.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(notifyContent_);\n                notifyContent_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000002;\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000004;\n              keepMsg_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_QuitGroupRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_QuitGroupRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.QuitGroupRequest.class, cn.wildfirechat.proto.WFCMessage.QuitGroupRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<QuitGroupRequest> PARSER =\n        new com.google.protobuf.AbstractParser<QuitGroupRequest>() {\n      public QuitGroupRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new QuitGroupRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<QuitGroupRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string group_id = 1;\n    public static final int GROUP_ID_FIELD_NUMBER = 1;\n    private java.lang.Object groupId_;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public boolean hasGroupId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public java.lang.String getGroupId() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          groupId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getGroupIdBytes() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        groupId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // repeated int32 to_line = 2;\n    public static final int TO_LINE_FIELD_NUMBER = 2;\n    private java.util.List<java.lang.Integer> toLine_;\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    public java.util.List<java.lang.Integer>\n        getToLineList() {\n      return toLine_;\n    }\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    public int getToLineCount() {\n      return toLine_.size();\n    }\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    public int getToLine(int index) {\n      return toLine_.get(index);\n    }\n\n    // optional .MessageContent notify_content = 3;\n    public static final int NOTIFY_CONTENT_FIELD_NUMBER = 3;\n    private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_;\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    public boolean hasNotifyContent() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n      return notifyContent_;\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n      return notifyContent_;\n    }\n\n    // optional int32 keep_msg = 4;\n    public static final int KEEP_MSG_FIELD_NUMBER = 4;\n    private int keepMsg_;\n    /**\n     * <code>optional int32 keep_msg = 4;</code>\n     */\n    public boolean hasKeepMsg() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional int32 keep_msg = 4;</code>\n     */\n    public int getKeepMsg() {\n      return keepMsg_;\n    }\n\n    private void initFields() {\n      groupId_ = \"\";\n      toLine_ = java.util.Collections.emptyList();\n      notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      keepMsg_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasGroupId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (hasNotifyContent()) {\n        if (!getNotifyContent().isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getGroupIdBytes());\n      }\n      for (int i = 0; i < toLine_.size(); i++) {\n        output.writeInt32(2, toLine_.get(i));\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeMessage(3, notifyContent_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt32(4, keepMsg_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getGroupIdBytes());\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < toLine_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeInt32SizeNoTag(toLine_.get(i));\n        }\n        size += dataSize;\n        size += 1 * getToLineList().size();\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(3, notifyContent_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(4, keepMsg_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.QuitGroupRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.QuitGroupRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.QuitGroupRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.QuitGroupRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.QuitGroupRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.QuitGroupRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.QuitGroupRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.QuitGroupRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.QuitGroupRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.QuitGroupRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.QuitGroupRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code QuitGroupRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.QuitGroupRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_QuitGroupRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_QuitGroupRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.QuitGroupRequest.class, cn.wildfirechat.proto.WFCMessage.QuitGroupRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.QuitGroupRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getNotifyContentFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        groupId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000002);\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000004);\n        keepMsg_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_QuitGroupRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.QuitGroupRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.QuitGroupRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.QuitGroupRequest build() {\n        cn.wildfirechat.proto.WFCMessage.QuitGroupRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.QuitGroupRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.QuitGroupRequest result = new cn.wildfirechat.proto.WFCMessage.QuitGroupRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.groupId_ = groupId_;\n        if (((bitField0_ & 0x00000002) == 0x00000002)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n          bitField0_ = (bitField0_ & ~0x00000002);\n        }\n        result.toLine_ = toLine_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        if (notifyContentBuilder_ == null) {\n          result.notifyContent_ = notifyContent_;\n        } else {\n          result.notifyContent_ = notifyContentBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.keepMsg_ = keepMsg_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.QuitGroupRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.QuitGroupRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.QuitGroupRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.QuitGroupRequest.getDefaultInstance()) return this;\n        if (other.hasGroupId()) {\n          bitField0_ |= 0x00000001;\n          groupId_ = other.groupId_;\n          onChanged();\n        }\n        if (!other.toLine_.isEmpty()) {\n          if (toLine_.isEmpty()) {\n            toLine_ = other.toLine_;\n            bitField0_ = (bitField0_ & ~0x00000002);\n          } else {\n            ensureToLineIsMutable();\n            toLine_.addAll(other.toLine_);\n          }\n          onChanged();\n        }\n        if (other.hasNotifyContent()) {\n          mergeNotifyContent(other.getNotifyContent());\n        }\n        if (other.hasKeepMsg()) {\n          setKeepMsg(other.getKeepMsg());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasGroupId()) {\n          \n          return false;\n        }\n        if (hasNotifyContent()) {\n          if (!getNotifyContent().isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.QuitGroupRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.QuitGroupRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string group_id = 1;\n      private java.lang.Object groupId_ = \"\";\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public boolean hasGroupId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public java.lang.String getGroupId() {\n        java.lang.Object ref = groupId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          groupId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getGroupIdBytes() {\n        java.lang.Object ref = groupId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          groupId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder clearGroupId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        groupId_ = getDefaultInstance().getGroupId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // repeated int32 to_line = 2;\n      private java.util.List<java.lang.Integer> toLine_ = java.util.Collections.emptyList();\n      private void ensureToLineIsMutable() {\n        if (!((bitField0_ & 0x00000002) == 0x00000002)) {\n          toLine_ = new java.util.ArrayList<java.lang.Integer>(toLine_);\n          bitField0_ |= 0x00000002;\n         }\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public java.util.List<java.lang.Integer>\n          getToLineList() {\n        return java.util.Collections.unmodifiableList(toLine_);\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public int getToLineCount() {\n        return toLine_.size();\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public int getToLine(int index) {\n        return toLine_.get(index);\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder setToLine(\n          int index, int value) {\n        ensureToLineIsMutable();\n        toLine_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder addToLine(int value) {\n        ensureToLineIsMutable();\n        toLine_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder addAllToLine(\n          java.lang.Iterable<? extends java.lang.Integer> values) {\n        ensureToLineIsMutable();\n        super.addAll(values, toLine_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder clearToLine() {\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000002);\n        onChanged();\n        return this;\n      }\n\n      // optional .MessageContent notify_content = 3;\n      private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> notifyContentBuilder_;\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public boolean hasNotifyContent() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          return notifyContent_;\n        } else {\n          return notifyContentBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder setNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          notifyContent_ = value;\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder setNotifyContent(\n          cn.wildfirechat.proto.WFCMessage.MessageContent.Builder builderForValue) {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = builderForValue.build();\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder mergeNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (((bitField0_ & 0x00000004) == 0x00000004) &&\n              notifyContent_ != cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) {\n            notifyContent_ =\n              cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder(notifyContent_).mergeFrom(value).buildPartial();\n          } else {\n            notifyContent_ = value;\n          }\n          onChanged();\n        } else {\n          notifyContentBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder clearNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n          onChanged();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent.Builder getNotifyContentBuilder() {\n        bitField0_ |= 0x00000004;\n        onChanged();\n        return getNotifyContentFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n        if (notifyContentBuilder_ != null) {\n          return notifyContentBuilder_.getMessageOrBuilder();\n        } else {\n          return notifyContent_;\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> \n          getNotifyContentFieldBuilder() {\n        if (notifyContentBuilder_ == null) {\n          notifyContentBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder>(\n                  notifyContent_,\n                  getParentForChildren(),\n                  isClean());\n          notifyContent_ = null;\n        }\n        return notifyContentBuilder_;\n      }\n\n      // optional int32 keep_msg = 4;\n      private int keepMsg_ ;\n      /**\n       * <code>optional int32 keep_msg = 4;</code>\n       */\n      public boolean hasKeepMsg() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional int32 keep_msg = 4;</code>\n       */\n      public int getKeepMsg() {\n        return keepMsg_;\n      }\n      /**\n       * <code>optional int32 keep_msg = 4;</code>\n       */\n      public Builder setKeepMsg(int value) {\n        bitField0_ |= 0x00000008;\n        keepMsg_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 keep_msg = 4;</code>\n       */\n      public Builder clearKeepMsg() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        keepMsg_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:QuitGroupRequest)\n    }\n\n    static {\n      defaultInstance = new QuitGroupRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:QuitGroupRequest)\n  }\n\n  public interface RemoveGroupMemberRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string group_id = 1;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    boolean hasGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    java.lang.String getGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getGroupIdBytes();\n\n    // repeated string removed_member = 2;\n    /**\n     * <code>repeated string removed_member = 2;</code>\n     */\n    java.util.List<java.lang.String>\n    getRemovedMemberList();\n    /**\n     * <code>repeated string removed_member = 2;</code>\n     */\n    int getRemovedMemberCount();\n    /**\n     * <code>repeated string removed_member = 2;</code>\n     */\n    java.lang.String getRemovedMember(int index);\n    /**\n     * <code>repeated string removed_member = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getRemovedMemberBytes(int index);\n\n    // repeated int32 to_line = 3;\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    java.util.List<java.lang.Integer> getToLineList();\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    int getToLineCount();\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    int getToLine(int index);\n\n    // optional .MessageContent notify_content = 4;\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    boolean hasNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder();\n  }\n  /**\n   * Protobuf type {@code RemoveGroupMemberRequest}\n   */\n  public static final class RemoveGroupMemberRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements RemoveGroupMemberRequestOrBuilder {\n    // Use RemoveGroupMemberRequest.newBuilder() to construct.\n    private RemoveGroupMemberRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private RemoveGroupMemberRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final RemoveGroupMemberRequest defaultInstance;\n    public static RemoveGroupMemberRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public RemoveGroupMemberRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private RemoveGroupMemberRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              groupId_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n                removedMember_ = new com.google.protobuf.LazyStringArrayList();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              removedMember_.add(input.readBytes());\n              break;\n            }\n            case 24: {\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              toLine_.add(input.readInt32());\n              break;\n            }\n            case 26: {\n              int length = input.readRawVarint32();\n              int limit = input.pushLimit(length);\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004) && input.getBytesUntilLimit() > 0) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              while (input.getBytesUntilLimit() > 0) {\n                toLine_.add(input.readInt32());\n              }\n              input.popLimit(limit);\n              break;\n            }\n            case 34: {\n              cn.wildfirechat.proto.WFCMessage.MessageContent.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                subBuilder = notifyContent_.toBuilder();\n              }\n              notifyContent_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.MessageContent.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(notifyContent_);\n                notifyContent_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000002;\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n          removedMember_ = new com.google.protobuf.UnmodifiableLazyStringList(removedMember_);\n        }\n        if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_RemoveGroupMemberRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_RemoveGroupMemberRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest.class, cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<RemoveGroupMemberRequest> PARSER =\n        new com.google.protobuf.AbstractParser<RemoveGroupMemberRequest>() {\n      public RemoveGroupMemberRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new RemoveGroupMemberRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<RemoveGroupMemberRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string group_id = 1;\n    public static final int GROUP_ID_FIELD_NUMBER = 1;\n    private java.lang.Object groupId_;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public boolean hasGroupId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public java.lang.String getGroupId() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          groupId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getGroupIdBytes() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        groupId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // repeated string removed_member = 2;\n    public static final int REMOVED_MEMBER_FIELD_NUMBER = 2;\n    private com.google.protobuf.LazyStringList removedMember_;\n    /**\n     * <code>repeated string removed_member = 2;</code>\n     */\n    public java.util.List<java.lang.String>\n        getRemovedMemberList() {\n      return removedMember_;\n    }\n    /**\n     * <code>repeated string removed_member = 2;</code>\n     */\n    public int getRemovedMemberCount() {\n      return removedMember_.size();\n    }\n    /**\n     * <code>repeated string removed_member = 2;</code>\n     */\n    public java.lang.String getRemovedMember(int index) {\n      return removedMember_.get(index);\n    }\n    /**\n     * <code>repeated string removed_member = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getRemovedMemberBytes(int index) {\n      return removedMember_.getByteString(index);\n    }\n\n    // repeated int32 to_line = 3;\n    public static final int TO_LINE_FIELD_NUMBER = 3;\n    private java.util.List<java.lang.Integer> toLine_;\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    public java.util.List<java.lang.Integer>\n        getToLineList() {\n      return toLine_;\n    }\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    public int getToLineCount() {\n      return toLine_.size();\n    }\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    public int getToLine(int index) {\n      return toLine_.get(index);\n    }\n\n    // optional .MessageContent notify_content = 4;\n    public static final int NOTIFY_CONTENT_FIELD_NUMBER = 4;\n    private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_;\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    public boolean hasNotifyContent() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n      return notifyContent_;\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n      return notifyContent_;\n    }\n\n    private void initFields() {\n      groupId_ = \"\";\n      removedMember_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      toLine_ = java.util.Collections.emptyList();\n      notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasGroupId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (hasNotifyContent()) {\n        if (!getNotifyContent().isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getGroupIdBytes());\n      }\n      for (int i = 0; i < removedMember_.size(); i++) {\n        output.writeBytes(2, removedMember_.getByteString(i));\n      }\n      for (int i = 0; i < toLine_.size(); i++) {\n        output.writeInt32(3, toLine_.get(i));\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeMessage(4, notifyContent_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getGroupIdBytes());\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < removedMember_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeBytesSizeNoTag(removedMember_.getByteString(i));\n        }\n        size += dataSize;\n        size += 1 * getRemovedMemberList().size();\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < toLine_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeInt32SizeNoTag(toLine_.get(i));\n        }\n        size += dataSize;\n        size += 1 * getToLineList().size();\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(4, notifyContent_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code RemoveGroupMemberRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_RemoveGroupMemberRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_RemoveGroupMemberRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest.class, cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getNotifyContentFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        groupId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        removedMember_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000004);\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_RemoveGroupMemberRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest build() {\n        cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest result = new cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.groupId_ = groupId_;\n        if (((bitField0_ & 0x00000002) == 0x00000002)) {\n          removedMember_ = new com.google.protobuf.UnmodifiableLazyStringList(\n              removedMember_);\n          bitField0_ = (bitField0_ & ~0x00000002);\n        }\n        result.removedMember_ = removedMember_;\n        if (((bitField0_ & 0x00000004) == 0x00000004)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n          bitField0_ = (bitField0_ & ~0x00000004);\n        }\n        result.toLine_ = toLine_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        if (notifyContentBuilder_ == null) {\n          result.notifyContent_ = notifyContent_;\n        } else {\n          result.notifyContent_ = notifyContentBuilder_.build();\n        }\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest.getDefaultInstance()) return this;\n        if (other.hasGroupId()) {\n          bitField0_ |= 0x00000001;\n          groupId_ = other.groupId_;\n          onChanged();\n        }\n        if (!other.removedMember_.isEmpty()) {\n          if (removedMember_.isEmpty()) {\n            removedMember_ = other.removedMember_;\n            bitField0_ = (bitField0_ & ~0x00000002);\n          } else {\n            ensureRemovedMemberIsMutable();\n            removedMember_.addAll(other.removedMember_);\n          }\n          onChanged();\n        }\n        if (!other.toLine_.isEmpty()) {\n          if (toLine_.isEmpty()) {\n            toLine_ = other.toLine_;\n            bitField0_ = (bitField0_ & ~0x00000004);\n          } else {\n            ensureToLineIsMutable();\n            toLine_.addAll(other.toLine_);\n          }\n          onChanged();\n        }\n        if (other.hasNotifyContent()) {\n          mergeNotifyContent(other.getNotifyContent());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasGroupId()) {\n          \n          return false;\n        }\n        if (hasNotifyContent()) {\n          if (!getNotifyContent().isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.RemoveGroupMemberRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string group_id = 1;\n      private java.lang.Object groupId_ = \"\";\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public boolean hasGroupId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public java.lang.String getGroupId() {\n        java.lang.Object ref = groupId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          groupId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getGroupIdBytes() {\n        java.lang.Object ref = groupId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          groupId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder clearGroupId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        groupId_ = getDefaultInstance().getGroupId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // repeated string removed_member = 2;\n      private com.google.protobuf.LazyStringList removedMember_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      private void ensureRemovedMemberIsMutable() {\n        if (!((bitField0_ & 0x00000002) == 0x00000002)) {\n          removedMember_ = new com.google.protobuf.LazyStringArrayList(removedMember_);\n          bitField0_ |= 0x00000002;\n         }\n      }\n      /**\n       * <code>repeated string removed_member = 2;</code>\n       */\n      public java.util.List<java.lang.String>\n          getRemovedMemberList() {\n        return java.util.Collections.unmodifiableList(removedMember_);\n      }\n      /**\n       * <code>repeated string removed_member = 2;</code>\n       */\n      public int getRemovedMemberCount() {\n        return removedMember_.size();\n      }\n      /**\n       * <code>repeated string removed_member = 2;</code>\n       */\n      public java.lang.String getRemovedMember(int index) {\n        return removedMember_.get(index);\n      }\n      /**\n       * <code>repeated string removed_member = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getRemovedMemberBytes(int index) {\n        return removedMember_.getByteString(index);\n      }\n      /**\n       * <code>repeated string removed_member = 2;</code>\n       */\n      public Builder setRemovedMember(\n          int index, java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureRemovedMemberIsMutable();\n        removedMember_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string removed_member = 2;</code>\n       */\n      public Builder addRemovedMember(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureRemovedMemberIsMutable();\n        removedMember_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string removed_member = 2;</code>\n       */\n      public Builder addAllRemovedMember(\n          java.lang.Iterable<java.lang.String> values) {\n        ensureRemovedMemberIsMutable();\n        super.addAll(values, removedMember_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string removed_member = 2;</code>\n       */\n      public Builder clearRemovedMember() {\n        removedMember_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string removed_member = 2;</code>\n       */\n      public Builder addRemovedMemberBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureRemovedMemberIsMutable();\n        removedMember_.add(value);\n        onChanged();\n        return this;\n      }\n\n      // repeated int32 to_line = 3;\n      private java.util.List<java.lang.Integer> toLine_ = java.util.Collections.emptyList();\n      private void ensureToLineIsMutable() {\n        if (!((bitField0_ & 0x00000004) == 0x00000004)) {\n          toLine_ = new java.util.ArrayList<java.lang.Integer>(toLine_);\n          bitField0_ |= 0x00000004;\n         }\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public java.util.List<java.lang.Integer>\n          getToLineList() {\n        return java.util.Collections.unmodifiableList(toLine_);\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public int getToLineCount() {\n        return toLine_.size();\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public int getToLine(int index) {\n        return toLine_.get(index);\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder setToLine(\n          int index, int value) {\n        ensureToLineIsMutable();\n        toLine_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder addToLine(int value) {\n        ensureToLineIsMutable();\n        toLine_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder addAllToLine(\n          java.lang.Iterable<? extends java.lang.Integer> values) {\n        ensureToLineIsMutable();\n        super.addAll(values, toLine_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder clearToLine() {\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000004);\n        onChanged();\n        return this;\n      }\n\n      // optional .MessageContent notify_content = 4;\n      private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> notifyContentBuilder_;\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public boolean hasNotifyContent() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          return notifyContent_;\n        } else {\n          return notifyContentBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder setNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          notifyContent_ = value;\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000008;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder setNotifyContent(\n          cn.wildfirechat.proto.WFCMessage.MessageContent.Builder builderForValue) {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = builderForValue.build();\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000008;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder mergeNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (((bitField0_ & 0x00000008) == 0x00000008) &&\n              notifyContent_ != cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) {\n            notifyContent_ =\n              cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder(notifyContent_).mergeFrom(value).buildPartial();\n          } else {\n            notifyContent_ = value;\n          }\n          onChanged();\n        } else {\n          notifyContentBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000008;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder clearNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n          onChanged();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent.Builder getNotifyContentBuilder() {\n        bitField0_ |= 0x00000008;\n        onChanged();\n        return getNotifyContentFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n        if (notifyContentBuilder_ != null) {\n          return notifyContentBuilder_.getMessageOrBuilder();\n        } else {\n          return notifyContent_;\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> \n          getNotifyContentFieldBuilder() {\n        if (notifyContentBuilder_ == null) {\n          notifyContentBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder>(\n                  notifyContent_,\n                  getParentForChildren(),\n                  isClean());\n          notifyContent_ = null;\n        }\n        return notifyContentBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:RemoveGroupMemberRequest)\n    }\n\n    static {\n      defaultInstance = new RemoveGroupMemberRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:RemoveGroupMemberRequest)\n  }\n\n  public interface TransferGroupRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string group_id = 1;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    boolean hasGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    java.lang.String getGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getGroupIdBytes();\n\n    // required string new_owner = 2;\n    /**\n     * <code>required string new_owner = 2;</code>\n     */\n    boolean hasNewOwner();\n    /**\n     * <code>required string new_owner = 2;</code>\n     */\n    java.lang.String getNewOwner();\n    /**\n     * <code>required string new_owner = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getNewOwnerBytes();\n\n    // repeated int32 to_line = 3;\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    java.util.List<java.lang.Integer> getToLineList();\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    int getToLineCount();\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    int getToLine(int index);\n\n    // optional .MessageContent notify_content = 4;\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    boolean hasNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder();\n  }\n  /**\n   * Protobuf type {@code TransferGroupRequest}\n   */\n  public static final class TransferGroupRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements TransferGroupRequestOrBuilder {\n    // Use TransferGroupRequest.newBuilder() to construct.\n    private TransferGroupRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private TransferGroupRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final TransferGroupRequest defaultInstance;\n    public static TransferGroupRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public TransferGroupRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private TransferGroupRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              groupId_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              newOwner_ = input.readBytes();\n              break;\n            }\n            case 24: {\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              toLine_.add(input.readInt32());\n              break;\n            }\n            case 26: {\n              int length = input.readRawVarint32();\n              int limit = input.pushLimit(length);\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004) && input.getBytesUntilLimit() > 0) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              while (input.getBytesUntilLimit() > 0) {\n                toLine_.add(input.readInt32());\n              }\n              input.popLimit(limit);\n              break;\n            }\n            case 34: {\n              cn.wildfirechat.proto.WFCMessage.MessageContent.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000004) == 0x00000004)) {\n                subBuilder = notifyContent_.toBuilder();\n              }\n              notifyContent_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.MessageContent.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(notifyContent_);\n                notifyContent_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000004;\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_TransferGroupRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_TransferGroupRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.TransferGroupRequest.class, cn.wildfirechat.proto.WFCMessage.TransferGroupRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<TransferGroupRequest> PARSER =\n        new com.google.protobuf.AbstractParser<TransferGroupRequest>() {\n      public TransferGroupRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new TransferGroupRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<TransferGroupRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string group_id = 1;\n    public static final int GROUP_ID_FIELD_NUMBER = 1;\n    private java.lang.Object groupId_;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public boolean hasGroupId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public java.lang.String getGroupId() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          groupId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getGroupIdBytes() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        groupId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string new_owner = 2;\n    public static final int NEW_OWNER_FIELD_NUMBER = 2;\n    private java.lang.Object newOwner_;\n    /**\n     * <code>required string new_owner = 2;</code>\n     */\n    public boolean hasNewOwner() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string new_owner = 2;</code>\n     */\n    public java.lang.String getNewOwner() {\n      java.lang.Object ref = newOwner_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          newOwner_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string new_owner = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getNewOwnerBytes() {\n      java.lang.Object ref = newOwner_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        newOwner_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // repeated int32 to_line = 3;\n    public static final int TO_LINE_FIELD_NUMBER = 3;\n    private java.util.List<java.lang.Integer> toLine_;\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    public java.util.List<java.lang.Integer>\n        getToLineList() {\n      return toLine_;\n    }\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    public int getToLineCount() {\n      return toLine_.size();\n    }\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    public int getToLine(int index) {\n      return toLine_.get(index);\n    }\n\n    // optional .MessageContent notify_content = 4;\n    public static final int NOTIFY_CONTENT_FIELD_NUMBER = 4;\n    private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_;\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    public boolean hasNotifyContent() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n      return notifyContent_;\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n      return notifyContent_;\n    }\n\n    private void initFields() {\n      groupId_ = \"\";\n      newOwner_ = \"\";\n      toLine_ = java.util.Collections.emptyList();\n      notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasGroupId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasNewOwner()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (hasNotifyContent()) {\n        if (!getNotifyContent().isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getGroupIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getNewOwnerBytes());\n      }\n      for (int i = 0; i < toLine_.size(); i++) {\n        output.writeInt32(3, toLine_.get(i));\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeMessage(4, notifyContent_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getGroupIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getNewOwnerBytes());\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < toLine_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeInt32SizeNoTag(toLine_.get(i));\n        }\n        size += dataSize;\n        size += 1 * getToLineList().size();\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(4, notifyContent_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.TransferGroupRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferGroupRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferGroupRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferGroupRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferGroupRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferGroupRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferGroupRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferGroupRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferGroupRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.TransferGroupRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.TransferGroupRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code TransferGroupRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.TransferGroupRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_TransferGroupRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_TransferGroupRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.TransferGroupRequest.class, cn.wildfirechat.proto.WFCMessage.TransferGroupRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.TransferGroupRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getNotifyContentFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        groupId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        newOwner_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000004);\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_TransferGroupRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.TransferGroupRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.TransferGroupRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.TransferGroupRequest build() {\n        cn.wildfirechat.proto.WFCMessage.TransferGroupRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.TransferGroupRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.TransferGroupRequest result = new cn.wildfirechat.proto.WFCMessage.TransferGroupRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.groupId_ = groupId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.newOwner_ = newOwner_;\n        if (((bitField0_ & 0x00000004) == 0x00000004)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n          bitField0_ = (bitField0_ & ~0x00000004);\n        }\n        result.toLine_ = toLine_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        if (notifyContentBuilder_ == null) {\n          result.notifyContent_ = notifyContent_;\n        } else {\n          result.notifyContent_ = notifyContentBuilder_.build();\n        }\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.TransferGroupRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.TransferGroupRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.TransferGroupRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.TransferGroupRequest.getDefaultInstance()) return this;\n        if (other.hasGroupId()) {\n          bitField0_ |= 0x00000001;\n          groupId_ = other.groupId_;\n          onChanged();\n        }\n        if (other.hasNewOwner()) {\n          bitField0_ |= 0x00000002;\n          newOwner_ = other.newOwner_;\n          onChanged();\n        }\n        if (!other.toLine_.isEmpty()) {\n          if (toLine_.isEmpty()) {\n            toLine_ = other.toLine_;\n            bitField0_ = (bitField0_ & ~0x00000004);\n          } else {\n            ensureToLineIsMutable();\n            toLine_.addAll(other.toLine_);\n          }\n          onChanged();\n        }\n        if (other.hasNotifyContent()) {\n          mergeNotifyContent(other.getNotifyContent());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasGroupId()) {\n          \n          return false;\n        }\n        if (!hasNewOwner()) {\n          \n          return false;\n        }\n        if (hasNotifyContent()) {\n          if (!getNotifyContent().isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.TransferGroupRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.TransferGroupRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string group_id = 1;\n      private java.lang.Object groupId_ = \"\";\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public boolean hasGroupId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public java.lang.String getGroupId() {\n        java.lang.Object ref = groupId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          groupId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getGroupIdBytes() {\n        java.lang.Object ref = groupId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          groupId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder clearGroupId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        groupId_ = getDefaultInstance().getGroupId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string new_owner = 2;\n      private java.lang.Object newOwner_ = \"\";\n      /**\n       * <code>required string new_owner = 2;</code>\n       */\n      public boolean hasNewOwner() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string new_owner = 2;</code>\n       */\n      public java.lang.String getNewOwner() {\n        java.lang.Object ref = newOwner_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          newOwner_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string new_owner = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getNewOwnerBytes() {\n        java.lang.Object ref = newOwner_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          newOwner_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string new_owner = 2;</code>\n       */\n      public Builder setNewOwner(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        newOwner_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string new_owner = 2;</code>\n       */\n      public Builder clearNewOwner() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        newOwner_ = getDefaultInstance().getNewOwner();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string new_owner = 2;</code>\n       */\n      public Builder setNewOwnerBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        newOwner_ = value;\n        onChanged();\n        return this;\n      }\n\n      // repeated int32 to_line = 3;\n      private java.util.List<java.lang.Integer> toLine_ = java.util.Collections.emptyList();\n      private void ensureToLineIsMutable() {\n        if (!((bitField0_ & 0x00000004) == 0x00000004)) {\n          toLine_ = new java.util.ArrayList<java.lang.Integer>(toLine_);\n          bitField0_ |= 0x00000004;\n         }\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public java.util.List<java.lang.Integer>\n          getToLineList() {\n        return java.util.Collections.unmodifiableList(toLine_);\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public int getToLineCount() {\n        return toLine_.size();\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public int getToLine(int index) {\n        return toLine_.get(index);\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder setToLine(\n          int index, int value) {\n        ensureToLineIsMutable();\n        toLine_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder addToLine(int value) {\n        ensureToLineIsMutable();\n        toLine_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder addAllToLine(\n          java.lang.Iterable<? extends java.lang.Integer> values) {\n        ensureToLineIsMutable();\n        super.addAll(values, toLine_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder clearToLine() {\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000004);\n        onChanged();\n        return this;\n      }\n\n      // optional .MessageContent notify_content = 4;\n      private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> notifyContentBuilder_;\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public boolean hasNotifyContent() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          return notifyContent_;\n        } else {\n          return notifyContentBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder setNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          notifyContent_ = value;\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000008;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder setNotifyContent(\n          cn.wildfirechat.proto.WFCMessage.MessageContent.Builder builderForValue) {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = builderForValue.build();\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000008;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder mergeNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (((bitField0_ & 0x00000008) == 0x00000008) &&\n              notifyContent_ != cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) {\n            notifyContent_ =\n              cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder(notifyContent_).mergeFrom(value).buildPartial();\n          } else {\n            notifyContent_ = value;\n          }\n          onChanged();\n        } else {\n          notifyContentBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000008;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder clearNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n          onChanged();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent.Builder getNotifyContentBuilder() {\n        bitField0_ |= 0x00000008;\n        onChanged();\n        return getNotifyContentFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n        if (notifyContentBuilder_ != null) {\n          return notifyContentBuilder_.getMessageOrBuilder();\n        } else {\n          return notifyContent_;\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> \n          getNotifyContentFieldBuilder() {\n        if (notifyContentBuilder_ == null) {\n          notifyContentBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder>(\n                  notifyContent_,\n                  getParentForChildren(),\n                  isClean());\n          notifyContent_ = null;\n        }\n        return notifyContentBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:TransferGroupRequest)\n    }\n\n    static {\n      defaultInstance = new TransferGroupRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:TransferGroupRequest)\n  }\n\n  public interface ModifyGroupMemberAliasOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string group_id = 1;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    boolean hasGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    java.lang.String getGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getGroupIdBytes();\n\n    // required string alias = 2;\n    /**\n     * <code>required string alias = 2;</code>\n     */\n    boolean hasAlias();\n    /**\n     * <code>required string alias = 2;</code>\n     */\n    java.lang.String getAlias();\n    /**\n     * <code>required string alias = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getAliasBytes();\n\n    // repeated int32 to_line = 3;\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    java.util.List<java.lang.Integer> getToLineList();\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    int getToLineCount();\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    int getToLine(int index);\n\n    // optional .MessageContent notify_content = 4;\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    boolean hasNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder();\n\n    // optional string member_id = 5;\n    /**\n     * <code>optional string member_id = 5;</code>\n     */\n    boolean hasMemberId();\n    /**\n     * <code>optional string member_id = 5;</code>\n     */\n    java.lang.String getMemberId();\n    /**\n     * <code>optional string member_id = 5;</code>\n     */\n    com.google.protobuf.ByteString\n        getMemberIdBytes();\n  }\n  /**\n   * Protobuf type {@code ModifyGroupMemberAlias}\n   */\n  public static final class ModifyGroupMemberAlias extends\n      com.google.protobuf.GeneratedMessage\n      implements ModifyGroupMemberAliasOrBuilder {\n    // Use ModifyGroupMemberAlias.newBuilder() to construct.\n    private ModifyGroupMemberAlias(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ModifyGroupMemberAlias(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ModifyGroupMemberAlias defaultInstance;\n    public static ModifyGroupMemberAlias getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ModifyGroupMemberAlias getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ModifyGroupMemberAlias(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              groupId_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              alias_ = input.readBytes();\n              break;\n            }\n            case 24: {\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              toLine_.add(input.readInt32());\n              break;\n            }\n            case 26: {\n              int length = input.readRawVarint32();\n              int limit = input.pushLimit(length);\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004) && input.getBytesUntilLimit() > 0) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              while (input.getBytesUntilLimit() > 0) {\n                toLine_.add(input.readInt32());\n              }\n              input.popLimit(limit);\n              break;\n            }\n            case 34: {\n              cn.wildfirechat.proto.WFCMessage.MessageContent.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000004) == 0x00000004)) {\n                subBuilder = notifyContent_.toBuilder();\n              }\n              notifyContent_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.MessageContent.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(notifyContent_);\n                notifyContent_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000004;\n              break;\n            }\n            case 42: {\n              bitField0_ |= 0x00000008;\n              memberId_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupMemberAlias_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupMemberAlias_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias.class, cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ModifyGroupMemberAlias> PARSER =\n        new com.google.protobuf.AbstractParser<ModifyGroupMemberAlias>() {\n      public ModifyGroupMemberAlias parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ModifyGroupMemberAlias(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ModifyGroupMemberAlias> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string group_id = 1;\n    public static final int GROUP_ID_FIELD_NUMBER = 1;\n    private java.lang.Object groupId_;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public boolean hasGroupId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public java.lang.String getGroupId() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          groupId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getGroupIdBytes() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        groupId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string alias = 2;\n    public static final int ALIAS_FIELD_NUMBER = 2;\n    private java.lang.Object alias_;\n    /**\n     * <code>required string alias = 2;</code>\n     */\n    public boolean hasAlias() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string alias = 2;</code>\n     */\n    public java.lang.String getAlias() {\n      java.lang.Object ref = alias_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          alias_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string alias = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getAliasBytes() {\n      java.lang.Object ref = alias_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        alias_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // repeated int32 to_line = 3;\n    public static final int TO_LINE_FIELD_NUMBER = 3;\n    private java.util.List<java.lang.Integer> toLine_;\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    public java.util.List<java.lang.Integer>\n        getToLineList() {\n      return toLine_;\n    }\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    public int getToLineCount() {\n      return toLine_.size();\n    }\n    /**\n     * <code>repeated int32 to_line = 3;</code>\n     */\n    public int getToLine(int index) {\n      return toLine_.get(index);\n    }\n\n    // optional .MessageContent notify_content = 4;\n    public static final int NOTIFY_CONTENT_FIELD_NUMBER = 4;\n    private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_;\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    public boolean hasNotifyContent() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n      return notifyContent_;\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 4;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n      return notifyContent_;\n    }\n\n    // optional string member_id = 5;\n    public static final int MEMBER_ID_FIELD_NUMBER = 5;\n    private java.lang.Object memberId_;\n    /**\n     * <code>optional string member_id = 5;</code>\n     */\n    public boolean hasMemberId() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional string member_id = 5;</code>\n     */\n    public java.lang.String getMemberId() {\n      java.lang.Object ref = memberId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          memberId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string member_id = 5;</code>\n     */\n    public com.google.protobuf.ByteString\n        getMemberIdBytes() {\n      java.lang.Object ref = memberId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        memberId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      groupId_ = \"\";\n      alias_ = \"\";\n      toLine_ = java.util.Collections.emptyList();\n      notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      memberId_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasGroupId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasAlias()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (hasNotifyContent()) {\n        if (!getNotifyContent().isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getGroupIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getAliasBytes());\n      }\n      for (int i = 0; i < toLine_.size(); i++) {\n        output.writeInt32(3, toLine_.get(i));\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeMessage(4, notifyContent_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(5, getMemberIdBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getGroupIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getAliasBytes());\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < toLine_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeInt32SizeNoTag(toLine_.get(i));\n        }\n        size += dataSize;\n        size += 1 * getToLineList().size();\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(4, notifyContent_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5, getMemberIdBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ModifyGroupMemberAlias}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAliasOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupMemberAlias_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupMemberAlias_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias.class, cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getNotifyContentFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        groupId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        alias_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000004);\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000008);\n        memberId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000010);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupMemberAlias_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias build() {\n        cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias result = new cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.groupId_ = groupId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.alias_ = alias_;\n        if (((bitField0_ & 0x00000004) == 0x00000004)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n          bitField0_ = (bitField0_ & ~0x00000004);\n        }\n        result.toLine_ = toLine_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        if (notifyContentBuilder_ == null) {\n          result.notifyContent_ = notifyContent_;\n        } else {\n          result.notifyContent_ = notifyContentBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.memberId_ = memberId_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias.getDefaultInstance()) return this;\n        if (other.hasGroupId()) {\n          bitField0_ |= 0x00000001;\n          groupId_ = other.groupId_;\n          onChanged();\n        }\n        if (other.hasAlias()) {\n          bitField0_ |= 0x00000002;\n          alias_ = other.alias_;\n          onChanged();\n        }\n        if (!other.toLine_.isEmpty()) {\n          if (toLine_.isEmpty()) {\n            toLine_ = other.toLine_;\n            bitField0_ = (bitField0_ & ~0x00000004);\n          } else {\n            ensureToLineIsMutable();\n            toLine_.addAll(other.toLine_);\n          }\n          onChanged();\n        }\n        if (other.hasNotifyContent()) {\n          mergeNotifyContent(other.getNotifyContent());\n        }\n        if (other.hasMemberId()) {\n          bitField0_ |= 0x00000010;\n          memberId_ = other.memberId_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasGroupId()) {\n          \n          return false;\n        }\n        if (!hasAlias()) {\n          \n          return false;\n        }\n        if (hasNotifyContent()) {\n          if (!getNotifyContent().isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberAlias) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string group_id = 1;\n      private java.lang.Object groupId_ = \"\";\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public boolean hasGroupId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public java.lang.String getGroupId() {\n        java.lang.Object ref = groupId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          groupId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getGroupIdBytes() {\n        java.lang.Object ref = groupId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          groupId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder clearGroupId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        groupId_ = getDefaultInstance().getGroupId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string alias = 2;\n      private java.lang.Object alias_ = \"\";\n      /**\n       * <code>required string alias = 2;</code>\n       */\n      public boolean hasAlias() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string alias = 2;</code>\n       */\n      public java.lang.String getAlias() {\n        java.lang.Object ref = alias_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          alias_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string alias = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getAliasBytes() {\n        java.lang.Object ref = alias_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          alias_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string alias = 2;</code>\n       */\n      public Builder setAlias(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        alias_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string alias = 2;</code>\n       */\n      public Builder clearAlias() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        alias_ = getDefaultInstance().getAlias();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string alias = 2;</code>\n       */\n      public Builder setAliasBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        alias_ = value;\n        onChanged();\n        return this;\n      }\n\n      // repeated int32 to_line = 3;\n      private java.util.List<java.lang.Integer> toLine_ = java.util.Collections.emptyList();\n      private void ensureToLineIsMutable() {\n        if (!((bitField0_ & 0x00000004) == 0x00000004)) {\n          toLine_ = new java.util.ArrayList<java.lang.Integer>(toLine_);\n          bitField0_ |= 0x00000004;\n         }\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public java.util.List<java.lang.Integer>\n          getToLineList() {\n        return java.util.Collections.unmodifiableList(toLine_);\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public int getToLineCount() {\n        return toLine_.size();\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public int getToLine(int index) {\n        return toLine_.get(index);\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder setToLine(\n          int index, int value) {\n        ensureToLineIsMutable();\n        toLine_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder addToLine(int value) {\n        ensureToLineIsMutable();\n        toLine_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder addAllToLine(\n          java.lang.Iterable<? extends java.lang.Integer> values) {\n        ensureToLineIsMutable();\n        super.addAll(values, toLine_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 3;</code>\n       */\n      public Builder clearToLine() {\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000004);\n        onChanged();\n        return this;\n      }\n\n      // optional .MessageContent notify_content = 4;\n      private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> notifyContentBuilder_;\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public boolean hasNotifyContent() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          return notifyContent_;\n        } else {\n          return notifyContentBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder setNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          notifyContent_ = value;\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000008;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder setNotifyContent(\n          cn.wildfirechat.proto.WFCMessage.MessageContent.Builder builderForValue) {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = builderForValue.build();\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000008;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder mergeNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (((bitField0_ & 0x00000008) == 0x00000008) &&\n              notifyContent_ != cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) {\n            notifyContent_ =\n              cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder(notifyContent_).mergeFrom(value).buildPartial();\n          } else {\n            notifyContent_ = value;\n          }\n          onChanged();\n        } else {\n          notifyContentBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000008;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public Builder clearNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n          onChanged();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent.Builder getNotifyContentBuilder() {\n        bitField0_ |= 0x00000008;\n        onChanged();\n        return getNotifyContentFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n        if (notifyContentBuilder_ != null) {\n          return notifyContentBuilder_.getMessageOrBuilder();\n        } else {\n          return notifyContent_;\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 4;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> \n          getNotifyContentFieldBuilder() {\n        if (notifyContentBuilder_ == null) {\n          notifyContentBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder>(\n                  notifyContent_,\n                  getParentForChildren(),\n                  isClean());\n          notifyContent_ = null;\n        }\n        return notifyContentBuilder_;\n      }\n\n      // optional string member_id = 5;\n      private java.lang.Object memberId_ = \"\";\n      /**\n       * <code>optional string member_id = 5;</code>\n       */\n      public boolean hasMemberId() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional string member_id = 5;</code>\n       */\n      public java.lang.String getMemberId() {\n        java.lang.Object ref = memberId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          memberId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string member_id = 5;</code>\n       */\n      public com.google.protobuf.ByteString\n          getMemberIdBytes() {\n        java.lang.Object ref = memberId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          memberId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string member_id = 5;</code>\n       */\n      public Builder setMemberId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        memberId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string member_id = 5;</code>\n       */\n      public Builder clearMemberId() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        memberId_ = getDefaultInstance().getMemberId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string member_id = 5;</code>\n       */\n      public Builder setMemberIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        memberId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ModifyGroupMemberAlias)\n    }\n\n    static {\n      defaultInstance = new ModifyGroupMemberAlias(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ModifyGroupMemberAlias)\n  }\n\n  public interface ModifyGroupMemberExtraOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string group_id = 1;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    boolean hasGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    java.lang.String getGroupId();\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getGroupIdBytes();\n\n    // repeated int32 to_line = 2;\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    java.util.List<java.lang.Integer> getToLineList();\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    int getToLineCount();\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    int getToLine(int index);\n\n    // optional .MessageContent notify_content = 3;\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    boolean hasNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent();\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder();\n\n    // optional string extra = 4;\n    /**\n     * <code>optional string extra = 4;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 4;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n\n    // optional string member_id = 5;\n    /**\n     * <code>optional string member_id = 5;</code>\n     */\n    boolean hasMemberId();\n    /**\n     * <code>optional string member_id = 5;</code>\n     */\n    java.lang.String getMemberId();\n    /**\n     * <code>optional string member_id = 5;</code>\n     */\n    com.google.protobuf.ByteString\n        getMemberIdBytes();\n  }\n  /**\n   * Protobuf type {@code ModifyGroupMemberExtra}\n   */\n  public static final class ModifyGroupMemberExtra extends\n      com.google.protobuf.GeneratedMessage\n      implements ModifyGroupMemberExtraOrBuilder {\n    // Use ModifyGroupMemberExtra.newBuilder() to construct.\n    private ModifyGroupMemberExtra(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ModifyGroupMemberExtra(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ModifyGroupMemberExtra defaultInstance;\n    public static ModifyGroupMemberExtra getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ModifyGroupMemberExtra getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ModifyGroupMemberExtra(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              groupId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              toLine_.add(input.readInt32());\n              break;\n            }\n            case 18: {\n              int length = input.readRawVarint32();\n              int limit = input.pushLimit(length);\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002) && input.getBytesUntilLimit() > 0) {\n                toLine_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              while (input.getBytesUntilLimit() > 0) {\n                toLine_.add(input.readInt32());\n              }\n              input.popLimit(limit);\n              break;\n            }\n            case 26: {\n              cn.wildfirechat.proto.WFCMessage.MessageContent.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                subBuilder = notifyContent_.toBuilder();\n              }\n              notifyContent_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.MessageContent.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(notifyContent_);\n                notifyContent_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000002;\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000004;\n              extra_ = input.readBytes();\n              break;\n            }\n            case 42: {\n              bitField0_ |= 0x00000008;\n              memberId_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupMemberExtra_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupMemberExtra_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra.class, cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ModifyGroupMemberExtra> PARSER =\n        new com.google.protobuf.AbstractParser<ModifyGroupMemberExtra>() {\n      public ModifyGroupMemberExtra parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ModifyGroupMemberExtra(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ModifyGroupMemberExtra> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string group_id = 1;\n    public static final int GROUP_ID_FIELD_NUMBER = 1;\n    private java.lang.Object groupId_;\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public boolean hasGroupId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public java.lang.String getGroupId() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          groupId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string group_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getGroupIdBytes() {\n      java.lang.Object ref = groupId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        groupId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // repeated int32 to_line = 2;\n    public static final int TO_LINE_FIELD_NUMBER = 2;\n    private java.util.List<java.lang.Integer> toLine_;\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    public java.util.List<java.lang.Integer>\n        getToLineList() {\n      return toLine_;\n    }\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    public int getToLineCount() {\n      return toLine_.size();\n    }\n    /**\n     * <code>repeated int32 to_line = 2;</code>\n     */\n    public int getToLine(int index) {\n      return toLine_.get(index);\n    }\n\n    // optional .MessageContent notify_content = 3;\n    public static final int NOTIFY_CONTENT_FIELD_NUMBER = 3;\n    private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_;\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    public boolean hasNotifyContent() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n      return notifyContent_;\n    }\n    /**\n     * <code>optional .MessageContent notify_content = 3;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n      return notifyContent_;\n    }\n\n    // optional string extra = 4;\n    public static final int EXTRA_FIELD_NUMBER = 4;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 4;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string extra = 4;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string member_id = 5;\n    public static final int MEMBER_ID_FIELD_NUMBER = 5;\n    private java.lang.Object memberId_;\n    /**\n     * <code>optional string member_id = 5;</code>\n     */\n    public boolean hasMemberId() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional string member_id = 5;</code>\n     */\n    public java.lang.String getMemberId() {\n      java.lang.Object ref = memberId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          memberId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string member_id = 5;</code>\n     */\n    public com.google.protobuf.ByteString\n        getMemberIdBytes() {\n      java.lang.Object ref = memberId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        memberId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      groupId_ = \"\";\n      toLine_ = java.util.Collections.emptyList();\n      notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      extra_ = \"\";\n      memberId_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasGroupId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (hasNotifyContent()) {\n        if (!getNotifyContent().isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getGroupIdBytes());\n      }\n      for (int i = 0; i < toLine_.size(); i++) {\n        output.writeInt32(2, toLine_.get(i));\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeMessage(3, notifyContent_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(4, getExtraBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(5, getMemberIdBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getGroupIdBytes());\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < toLine_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeInt32SizeNoTag(toLine_.get(i));\n        }\n        size += dataSize;\n        size += 1 * getToLineList().size();\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(3, notifyContent_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, getExtraBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5, getMemberIdBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ModifyGroupMemberExtra}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtraOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupMemberExtra_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupMemberExtra_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra.class, cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getNotifyContentFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        groupId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000002);\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000004);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        memberId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000010);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyGroupMemberExtra_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra build() {\n        cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra result = new cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.groupId_ = groupId_;\n        if (((bitField0_ & 0x00000002) == 0x00000002)) {\n          toLine_ = java.util.Collections.unmodifiableList(toLine_);\n          bitField0_ = (bitField0_ & ~0x00000002);\n        }\n        result.toLine_ = toLine_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        if (notifyContentBuilder_ == null) {\n          result.notifyContent_ = notifyContent_;\n        } else {\n          result.notifyContent_ = notifyContentBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.extra_ = extra_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.memberId_ = memberId_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra.getDefaultInstance()) return this;\n        if (other.hasGroupId()) {\n          bitField0_ |= 0x00000001;\n          groupId_ = other.groupId_;\n          onChanged();\n        }\n        if (!other.toLine_.isEmpty()) {\n          if (toLine_.isEmpty()) {\n            toLine_ = other.toLine_;\n            bitField0_ = (bitField0_ & ~0x00000002);\n          } else {\n            ensureToLineIsMutable();\n            toLine_.addAll(other.toLine_);\n          }\n          onChanged();\n        }\n        if (other.hasNotifyContent()) {\n          mergeNotifyContent(other.getNotifyContent());\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000008;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        if (other.hasMemberId()) {\n          bitField0_ |= 0x00000010;\n          memberId_ = other.memberId_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasGroupId()) {\n          \n          return false;\n        }\n        if (hasNotifyContent()) {\n          if (!getNotifyContent().isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ModifyGroupMemberExtra) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string group_id = 1;\n      private java.lang.Object groupId_ = \"\";\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public boolean hasGroupId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public java.lang.String getGroupId() {\n        java.lang.Object ref = groupId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          groupId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getGroupIdBytes() {\n        java.lang.Object ref = groupId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          groupId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder clearGroupId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        groupId_ = getDefaultInstance().getGroupId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string group_id = 1;</code>\n       */\n      public Builder setGroupIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        groupId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // repeated int32 to_line = 2;\n      private java.util.List<java.lang.Integer> toLine_ = java.util.Collections.emptyList();\n      private void ensureToLineIsMutable() {\n        if (!((bitField0_ & 0x00000002) == 0x00000002)) {\n          toLine_ = new java.util.ArrayList<java.lang.Integer>(toLine_);\n          bitField0_ |= 0x00000002;\n         }\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public java.util.List<java.lang.Integer>\n          getToLineList() {\n        return java.util.Collections.unmodifiableList(toLine_);\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public int getToLineCount() {\n        return toLine_.size();\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public int getToLine(int index) {\n        return toLine_.get(index);\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder setToLine(\n          int index, int value) {\n        ensureToLineIsMutable();\n        toLine_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder addToLine(int value) {\n        ensureToLineIsMutable();\n        toLine_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder addAllToLine(\n          java.lang.Iterable<? extends java.lang.Integer> values) {\n        ensureToLineIsMutable();\n        super.addAll(values, toLine_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 to_line = 2;</code>\n       */\n      public Builder clearToLine() {\n        toLine_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000002);\n        onChanged();\n        return this;\n      }\n\n      // optional .MessageContent notify_content = 3;\n      private cn.wildfirechat.proto.WFCMessage.MessageContent notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> notifyContentBuilder_;\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public boolean hasNotifyContent() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          return notifyContent_;\n        } else {\n          return notifyContentBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder setNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          notifyContent_ = value;\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder setNotifyContent(\n          cn.wildfirechat.proto.WFCMessage.MessageContent.Builder builderForValue) {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = builderForValue.build();\n          onChanged();\n        } else {\n          notifyContentBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder mergeNotifyContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (notifyContentBuilder_ == null) {\n          if (((bitField0_ & 0x00000004) == 0x00000004) &&\n              notifyContent_ != cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) {\n            notifyContent_ =\n              cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder(notifyContent_).mergeFrom(value).buildPartial();\n          } else {\n            notifyContent_ = value;\n          }\n          onChanged();\n        } else {\n          notifyContentBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000004;\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public Builder clearNotifyContent() {\n        if (notifyContentBuilder_ == null) {\n          notifyContent_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n          onChanged();\n        } else {\n          notifyContentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent.Builder getNotifyContentBuilder() {\n        bitField0_ |= 0x00000004;\n        onChanged();\n        return getNotifyContentFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getNotifyContentOrBuilder() {\n        if (notifyContentBuilder_ != null) {\n          return notifyContentBuilder_.getMessageOrBuilder();\n        } else {\n          return notifyContent_;\n        }\n      }\n      /**\n       * <code>optional .MessageContent notify_content = 3;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> \n          getNotifyContentFieldBuilder() {\n        if (notifyContentBuilder_ == null) {\n          notifyContentBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder>(\n                  notifyContent_,\n                  getParentForChildren(),\n                  isClean());\n          notifyContent_ = null;\n        }\n        return notifyContentBuilder_;\n      }\n\n      // optional string extra = 4;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 4;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional string extra = 4;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 4;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 4;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 4;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string member_id = 5;\n      private java.lang.Object memberId_ = \"\";\n      /**\n       * <code>optional string member_id = 5;</code>\n       */\n      public boolean hasMemberId() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional string member_id = 5;</code>\n       */\n      public java.lang.String getMemberId() {\n        java.lang.Object ref = memberId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          memberId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string member_id = 5;</code>\n       */\n      public com.google.protobuf.ByteString\n          getMemberIdBytes() {\n        java.lang.Object ref = memberId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          memberId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string member_id = 5;</code>\n       */\n      public Builder setMemberId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        memberId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string member_id = 5;</code>\n       */\n      public Builder clearMemberId() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        memberId_ = getDefaultInstance().getMemberId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string member_id = 5;</code>\n       */\n      public Builder setMemberIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        memberId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ModifyGroupMemberExtra)\n    }\n\n    static {\n      defaultInstance = new ModifyGroupMemberExtra(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ModifyGroupMemberExtra)\n  }\n\n  public interface UserSettingEntryOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int32 scope = 1;\n    /**\n     * <code>required int32 scope = 1;</code>\n     */\n    boolean hasScope();\n    /**\n     * <code>required int32 scope = 1;</code>\n     */\n    int getScope();\n\n    // required string key = 2;\n    /**\n     * <code>required string key = 2;</code>\n     */\n    boolean hasKey();\n    /**\n     * <code>required string key = 2;</code>\n     */\n    java.lang.String getKey();\n    /**\n     * <code>required string key = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getKeyBytes();\n\n    // required string value = 3;\n    /**\n     * <code>required string value = 3;</code>\n     */\n    boolean hasValue();\n    /**\n     * <code>required string value = 3;</code>\n     */\n    java.lang.String getValue();\n    /**\n     * <code>required string value = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getValueBytes();\n\n    // required int64 update_dt = 4;\n    /**\n     * <code>required int64 update_dt = 4;</code>\n     */\n    boolean hasUpdateDt();\n    /**\n     * <code>required int64 update_dt = 4;</code>\n     */\n    long getUpdateDt();\n  }\n  /**\n   * Protobuf type {@code UserSettingEntry}\n   */\n  public static final class UserSettingEntry extends\n      com.google.protobuf.GeneratedMessage\n      implements UserSettingEntryOrBuilder {\n    // Use UserSettingEntry.newBuilder() to construct.\n    private UserSettingEntry(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private UserSettingEntry(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final UserSettingEntry defaultInstance;\n    public static UserSettingEntry getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public UserSettingEntry getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private UserSettingEntry(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              scope_ = input.readInt32();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              key_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              value_ = input.readBytes();\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000008;\n              updateDt_ = input.readInt64();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_UserSettingEntry_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_UserSettingEntry_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.UserSettingEntry.class, cn.wildfirechat.proto.WFCMessage.UserSettingEntry.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<UserSettingEntry> PARSER =\n        new com.google.protobuf.AbstractParser<UserSettingEntry>() {\n      public UserSettingEntry parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new UserSettingEntry(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<UserSettingEntry> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int32 scope = 1;\n    public static final int SCOPE_FIELD_NUMBER = 1;\n    private int scope_;\n    /**\n     * <code>required int32 scope = 1;</code>\n     */\n    public boolean hasScope() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int32 scope = 1;</code>\n     */\n    public int getScope() {\n      return scope_;\n    }\n\n    // required string key = 2;\n    public static final int KEY_FIELD_NUMBER = 2;\n    private java.lang.Object key_;\n    /**\n     * <code>required string key = 2;</code>\n     */\n    public boolean hasKey() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string key = 2;</code>\n     */\n    public java.lang.String getKey() {\n      java.lang.Object ref = key_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          key_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string key = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getKeyBytes() {\n      java.lang.Object ref = key_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        key_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string value = 3;\n    public static final int VALUE_FIELD_NUMBER = 3;\n    private java.lang.Object value_;\n    /**\n     * <code>required string value = 3;</code>\n     */\n    public boolean hasValue() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required string value = 3;</code>\n     */\n    public java.lang.String getValue() {\n      java.lang.Object ref = value_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          value_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string value = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getValueBytes() {\n      java.lang.Object ref = value_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        value_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int64 update_dt = 4;\n    public static final int UPDATE_DT_FIELD_NUMBER = 4;\n    private long updateDt_;\n    /**\n     * <code>required int64 update_dt = 4;</code>\n     */\n    public boolean hasUpdateDt() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>required int64 update_dt = 4;</code>\n     */\n    public long getUpdateDt() {\n      return updateDt_;\n    }\n\n    private void initFields() {\n      scope_ = 0;\n      key_ = \"\";\n      value_ = \"\";\n      updateDt_ = 0L;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasScope()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasKey()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasValue()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasUpdateDt()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, scope_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getKeyBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getValueBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeInt64(4, updateDt_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, scope_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getKeyBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getValueBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(4, updateDt_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.UserSettingEntry parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserSettingEntry parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserSettingEntry parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserSettingEntry parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserSettingEntry parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserSettingEntry parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserSettingEntry parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserSettingEntry parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserSettingEntry parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.UserSettingEntry parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.UserSettingEntry prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code UserSettingEntry}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.UserSettingEntryOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_UserSettingEntry_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_UserSettingEntry_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.UserSettingEntry.class, cn.wildfirechat.proto.WFCMessage.UserSettingEntry.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.UserSettingEntry.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        scope_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        key_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        value_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        updateDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_UserSettingEntry_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.UserSettingEntry getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.UserSettingEntry.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.UserSettingEntry build() {\n        cn.wildfirechat.proto.WFCMessage.UserSettingEntry result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.UserSettingEntry buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.UserSettingEntry result = new cn.wildfirechat.proto.WFCMessage.UserSettingEntry(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.scope_ = scope_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.key_ = key_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.value_ = value_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.updateDt_ = updateDt_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.UserSettingEntry) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.UserSettingEntry)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.UserSettingEntry other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.UserSettingEntry.getDefaultInstance()) return this;\n        if (other.hasScope()) {\n          setScope(other.getScope());\n        }\n        if (other.hasKey()) {\n          bitField0_ |= 0x00000002;\n          key_ = other.key_;\n          onChanged();\n        }\n        if (other.hasValue()) {\n          bitField0_ |= 0x00000004;\n          value_ = other.value_;\n          onChanged();\n        }\n        if (other.hasUpdateDt()) {\n          setUpdateDt(other.getUpdateDt());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasScope()) {\n          \n          return false;\n        }\n        if (!hasKey()) {\n          \n          return false;\n        }\n        if (!hasValue()) {\n          \n          return false;\n        }\n        if (!hasUpdateDt()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.UserSettingEntry parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.UserSettingEntry) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int32 scope = 1;\n      private int scope_ ;\n      /**\n       * <code>required int32 scope = 1;</code>\n       */\n      public boolean hasScope() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int32 scope = 1;</code>\n       */\n      public int getScope() {\n        return scope_;\n      }\n      /**\n       * <code>required int32 scope = 1;</code>\n       */\n      public Builder setScope(int value) {\n        bitField0_ |= 0x00000001;\n        scope_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 scope = 1;</code>\n       */\n      public Builder clearScope() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        scope_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required string key = 2;\n      private java.lang.Object key_ = \"\";\n      /**\n       * <code>required string key = 2;</code>\n       */\n      public boolean hasKey() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string key = 2;</code>\n       */\n      public java.lang.String getKey() {\n        java.lang.Object ref = key_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          key_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string key = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getKeyBytes() {\n        java.lang.Object ref = key_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          key_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string key = 2;</code>\n       */\n      public Builder setKey(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        key_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string key = 2;</code>\n       */\n      public Builder clearKey() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        key_ = getDefaultInstance().getKey();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string key = 2;</code>\n       */\n      public Builder setKeyBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        key_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string value = 3;\n      private java.lang.Object value_ = \"\";\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public boolean hasValue() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public java.lang.String getValue() {\n        java.lang.Object ref = value_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          value_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getValueBytes() {\n        java.lang.Object ref = value_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          value_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public Builder setValue(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public Builder clearValue() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        value_ = getDefaultInstance().getValue();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public Builder setValueBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int64 update_dt = 4;\n      private long updateDt_ ;\n      /**\n       * <code>required int64 update_dt = 4;</code>\n       */\n      public boolean hasUpdateDt() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>required int64 update_dt = 4;</code>\n       */\n      public long getUpdateDt() {\n        return updateDt_;\n      }\n      /**\n       * <code>required int64 update_dt = 4;</code>\n       */\n      public Builder setUpdateDt(long value) {\n        bitField0_ |= 0x00000008;\n        updateDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 update_dt = 4;</code>\n       */\n      public Builder clearUpdateDt() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        updateDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:UserSettingEntry)\n    }\n\n    static {\n      defaultInstance = new UserSettingEntry(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:UserSettingEntry)\n  }\n\n  public interface ModifyUserSettingReqOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int32 scope = 1;\n    /**\n     * <code>required int32 scope = 1;</code>\n     */\n    boolean hasScope();\n    /**\n     * <code>required int32 scope = 1;</code>\n     */\n    int getScope();\n\n    // required string key = 2;\n    /**\n     * <code>required string key = 2;</code>\n     */\n    boolean hasKey();\n    /**\n     * <code>required string key = 2;</code>\n     */\n    java.lang.String getKey();\n    /**\n     * <code>required string key = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getKeyBytes();\n\n    // required string value = 3;\n    /**\n     * <code>required string value = 3;</code>\n     */\n    boolean hasValue();\n    /**\n     * <code>required string value = 3;</code>\n     */\n    java.lang.String getValue();\n    /**\n     * <code>required string value = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getValueBytes();\n  }\n  /**\n   * Protobuf type {@code ModifyUserSettingReq}\n   */\n  public static final class ModifyUserSettingReq extends\n      com.google.protobuf.GeneratedMessage\n      implements ModifyUserSettingReqOrBuilder {\n    // Use ModifyUserSettingReq.newBuilder() to construct.\n    private ModifyUserSettingReq(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ModifyUserSettingReq(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ModifyUserSettingReq defaultInstance;\n    public static ModifyUserSettingReq getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ModifyUserSettingReq getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ModifyUserSettingReq(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              scope_ = input.readInt32();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              key_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              value_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyUserSettingReq_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyUserSettingReq_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq.class, cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ModifyUserSettingReq> PARSER =\n        new com.google.protobuf.AbstractParser<ModifyUserSettingReq>() {\n      public ModifyUserSettingReq parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ModifyUserSettingReq(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ModifyUserSettingReq> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int32 scope = 1;\n    public static final int SCOPE_FIELD_NUMBER = 1;\n    private int scope_;\n    /**\n     * <code>required int32 scope = 1;</code>\n     */\n    public boolean hasScope() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int32 scope = 1;</code>\n     */\n    public int getScope() {\n      return scope_;\n    }\n\n    // required string key = 2;\n    public static final int KEY_FIELD_NUMBER = 2;\n    private java.lang.Object key_;\n    /**\n     * <code>required string key = 2;</code>\n     */\n    public boolean hasKey() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string key = 2;</code>\n     */\n    public java.lang.String getKey() {\n      java.lang.Object ref = key_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          key_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string key = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getKeyBytes() {\n      java.lang.Object ref = key_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        key_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string value = 3;\n    public static final int VALUE_FIELD_NUMBER = 3;\n    private java.lang.Object value_;\n    /**\n     * <code>required string value = 3;</code>\n     */\n    public boolean hasValue() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required string value = 3;</code>\n     */\n    public java.lang.String getValue() {\n      java.lang.Object ref = value_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          value_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string value = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getValueBytes() {\n      java.lang.Object ref = value_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        value_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      scope_ = 0;\n      key_ = \"\";\n      value_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasScope()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasKey()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasValue()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, scope_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getKeyBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getValueBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, scope_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getKeyBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getValueBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ModifyUserSettingReq}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReqOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyUserSettingReq_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyUserSettingReq_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq.class, cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        scope_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        key_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        value_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ModifyUserSettingReq_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq build() {\n        cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq result = new cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.scope_ = scope_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.key_ = key_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.value_ = value_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq.getDefaultInstance()) return this;\n        if (other.hasScope()) {\n          setScope(other.getScope());\n        }\n        if (other.hasKey()) {\n          bitField0_ |= 0x00000002;\n          key_ = other.key_;\n          onChanged();\n        }\n        if (other.hasValue()) {\n          bitField0_ |= 0x00000004;\n          value_ = other.value_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasScope()) {\n          \n          return false;\n        }\n        if (!hasKey()) {\n          \n          return false;\n        }\n        if (!hasValue()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ModifyUserSettingReq) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int32 scope = 1;\n      private int scope_ ;\n      /**\n       * <code>required int32 scope = 1;</code>\n       */\n      public boolean hasScope() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int32 scope = 1;</code>\n       */\n      public int getScope() {\n        return scope_;\n      }\n      /**\n       * <code>required int32 scope = 1;</code>\n       */\n      public Builder setScope(int value) {\n        bitField0_ |= 0x00000001;\n        scope_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 scope = 1;</code>\n       */\n      public Builder clearScope() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        scope_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required string key = 2;\n      private java.lang.Object key_ = \"\";\n      /**\n       * <code>required string key = 2;</code>\n       */\n      public boolean hasKey() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string key = 2;</code>\n       */\n      public java.lang.String getKey() {\n        java.lang.Object ref = key_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          key_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string key = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getKeyBytes() {\n        java.lang.Object ref = key_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          key_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string key = 2;</code>\n       */\n      public Builder setKey(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        key_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string key = 2;</code>\n       */\n      public Builder clearKey() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        key_ = getDefaultInstance().getKey();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string key = 2;</code>\n       */\n      public Builder setKeyBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        key_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string value = 3;\n      private java.lang.Object value_ = \"\";\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public boolean hasValue() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public java.lang.String getValue() {\n        java.lang.Object ref = value_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          value_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getValueBytes() {\n        java.lang.Object ref = value_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          value_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public Builder setValue(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public Builder clearValue() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        value_ = getDefaultInstance().getValue();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string value = 3;</code>\n       */\n      public Builder setValueBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ModifyUserSettingReq)\n    }\n\n    static {\n      defaultInstance = new ModifyUserSettingReq(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ModifyUserSettingReq)\n  }\n\n  public interface VersionOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int64 version = 1;\n    /**\n     * <code>required int64 version = 1;</code>\n     */\n    boolean hasVersion();\n    /**\n     * <code>required int64 version = 1;</code>\n     */\n    long getVersion();\n  }\n  /**\n   * Protobuf type {@code Version}\n   */\n  public static final class Version extends\n      com.google.protobuf.GeneratedMessage\n      implements VersionOrBuilder {\n    // Use Version.newBuilder() to construct.\n    private Version(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private Version(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final Version defaultInstance;\n    public static Version getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public Version getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Version(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              version_ = input.readInt64();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_Version_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_Version_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.Version.class, cn.wildfirechat.proto.WFCMessage.Version.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<Version> PARSER =\n        new com.google.protobuf.AbstractParser<Version>() {\n      public Version parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Version(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Version> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int64 version = 1;\n    public static final int VERSION_FIELD_NUMBER = 1;\n    private long version_;\n    /**\n     * <code>required int64 version = 1;</code>\n     */\n    public boolean hasVersion() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int64 version = 1;</code>\n     */\n    public long getVersion() {\n      return version_;\n    }\n\n    private void initFields() {\n      version_ = 0L;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasVersion()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt64(1, version_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, version_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.Version parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Version parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Version parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Version parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Version parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Version parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Version parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Version parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Version parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Version parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.Version prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code Version}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.VersionOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Version_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Version_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.Version.class, cn.wildfirechat.proto.WFCMessage.Version.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.Version.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        version_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Version_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Version getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.Version.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Version build() {\n        cn.wildfirechat.proto.WFCMessage.Version result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Version buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.Version result = new cn.wildfirechat.proto.WFCMessage.Version(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.version_ = version_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.Version) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.Version)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.Version other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.Version.getDefaultInstance()) return this;\n        if (other.hasVersion()) {\n          setVersion(other.getVersion());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasVersion()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.Version parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.Version) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int64 version = 1;\n      private long version_ ;\n      /**\n       * <code>required int64 version = 1;</code>\n       */\n      public boolean hasVersion() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int64 version = 1;</code>\n       */\n      public long getVersion() {\n        return version_;\n      }\n      /**\n       * <code>required int64 version = 1;</code>\n       */\n      public Builder setVersion(long value) {\n        bitField0_ |= 0x00000001;\n        version_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 version = 1;</code>\n       */\n      public Builder clearVersion() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        version_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:Version)\n    }\n\n    static {\n      defaultInstance = new Version(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:Version)\n  }\n\n  public interface GetUserSettingResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .UserSettingEntry entry = 1;\n    /**\n     * <code>repeated .UserSettingEntry entry = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.UserSettingEntry> \n        getEntryList();\n    /**\n     * <code>repeated .UserSettingEntry entry = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.UserSettingEntry getEntry(int index);\n    /**\n     * <code>repeated .UserSettingEntry entry = 1;</code>\n     */\n    int getEntryCount();\n    /**\n     * <code>repeated .UserSettingEntry entry = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.UserSettingEntryOrBuilder> \n        getEntryOrBuilderList();\n    /**\n     * <code>repeated .UserSettingEntry entry = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.UserSettingEntryOrBuilder getEntryOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code GetUserSettingResult}\n   */\n  public static final class GetUserSettingResult extends\n      com.google.protobuf.GeneratedMessage\n      implements GetUserSettingResultOrBuilder {\n    // Use GetUserSettingResult.newBuilder() to construct.\n    private GetUserSettingResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private GetUserSettingResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final GetUserSettingResult defaultInstance;\n    public static GetUserSettingResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public GetUserSettingResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private GetUserSettingResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                entry_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.UserSettingEntry>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              entry_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.UserSettingEntry.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          entry_ = java.util.Collections.unmodifiableList(entry_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetUserSettingResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetUserSettingResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.GetUserSettingResult.class, cn.wildfirechat.proto.WFCMessage.GetUserSettingResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<GetUserSettingResult> PARSER =\n        new com.google.protobuf.AbstractParser<GetUserSettingResult>() {\n      public GetUserSettingResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new GetUserSettingResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<GetUserSettingResult> getParserForType() {\n      return PARSER;\n    }\n\n    // repeated .UserSettingEntry entry = 1;\n    public static final int ENTRY_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.UserSettingEntry> entry_;\n    /**\n     * <code>repeated .UserSettingEntry entry = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.UserSettingEntry> getEntryList() {\n      return entry_;\n    }\n    /**\n     * <code>repeated .UserSettingEntry entry = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.UserSettingEntryOrBuilder> \n        getEntryOrBuilderList() {\n      return entry_;\n    }\n    /**\n     * <code>repeated .UserSettingEntry entry = 1;</code>\n     */\n    public int getEntryCount() {\n      return entry_.size();\n    }\n    /**\n     * <code>repeated .UserSettingEntry entry = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.UserSettingEntry getEntry(int index) {\n      return entry_.get(index);\n    }\n    /**\n     * <code>repeated .UserSettingEntry entry = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.UserSettingEntryOrBuilder getEntryOrBuilder(\n        int index) {\n      return entry_.get(index);\n    }\n\n    private void initFields() {\n      entry_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      for (int i = 0; i < getEntryCount(); i++) {\n        if (!getEntry(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < entry_.size(); i++) {\n        output.writeMessage(1, entry_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < entry_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, entry_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.GetUserSettingResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUserSettingResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUserSettingResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUserSettingResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUserSettingResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUserSettingResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUserSettingResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUserSettingResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUserSettingResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetUserSettingResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.GetUserSettingResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code GetUserSettingResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GetUserSettingResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetUserSettingResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetUserSettingResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.GetUserSettingResult.class, cn.wildfirechat.proto.WFCMessage.GetUserSettingResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.GetUserSettingResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getEntryFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (entryBuilder_ == null) {\n          entry_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          entryBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetUserSettingResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetUserSettingResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.GetUserSettingResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetUserSettingResult build() {\n        cn.wildfirechat.proto.WFCMessage.GetUserSettingResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetUserSettingResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.GetUserSettingResult result = new cn.wildfirechat.proto.WFCMessage.GetUserSettingResult(this);\n        int from_bitField0_ = bitField0_;\n        if (entryBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            entry_ = java.util.Collections.unmodifiableList(entry_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.entry_ = entry_;\n        } else {\n          result.entry_ = entryBuilder_.build();\n        }\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.GetUserSettingResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.GetUserSettingResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.GetUserSettingResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.GetUserSettingResult.getDefaultInstance()) return this;\n        if (entryBuilder_ == null) {\n          if (!other.entry_.isEmpty()) {\n            if (entry_.isEmpty()) {\n              entry_ = other.entry_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureEntryIsMutable();\n              entry_.addAll(other.entry_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.entry_.isEmpty()) {\n            if (entryBuilder_.isEmpty()) {\n              entryBuilder_.dispose();\n              entryBuilder_ = null;\n              entry_ = other.entry_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              entryBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getEntryFieldBuilder() : null;\n            } else {\n              entryBuilder_.addAllMessages(other.entry_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        for (int i = 0; i < getEntryCount(); i++) {\n          if (!getEntry(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.GetUserSettingResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.GetUserSettingResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .UserSettingEntry entry = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.UserSettingEntry> entry_ =\n        java.util.Collections.emptyList();\n      private void ensureEntryIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          entry_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.UserSettingEntry>(entry_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.UserSettingEntry, cn.wildfirechat.proto.WFCMessage.UserSettingEntry.Builder, cn.wildfirechat.proto.WFCMessage.UserSettingEntryOrBuilder> entryBuilder_;\n\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.UserSettingEntry> getEntryList() {\n        if (entryBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(entry_);\n        } else {\n          return entryBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public int getEntryCount() {\n        if (entryBuilder_ == null) {\n          return entry_.size();\n        } else {\n          return entryBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserSettingEntry getEntry(int index) {\n        if (entryBuilder_ == null) {\n          return entry_.get(index);\n        } else {\n          return entryBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public Builder setEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.UserSettingEntry value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.set(index, value);\n          onChanged();\n        } else {\n          entryBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public Builder setEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.UserSettingEntry.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public Builder addEntry(cn.wildfirechat.proto.WFCMessage.UserSettingEntry value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.add(value);\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public Builder addEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.UserSettingEntry value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.add(index, value);\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public Builder addEntry(\n          cn.wildfirechat.proto.WFCMessage.UserSettingEntry.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.add(builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public Builder addEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.UserSettingEntry.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public Builder addAllEntry(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.UserSettingEntry> values) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          super.addAll(values, entry_);\n          onChanged();\n        } else {\n          entryBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public Builder clearEntry() {\n        if (entryBuilder_ == null) {\n          entry_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          entryBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public Builder removeEntry(int index) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.remove(index);\n          onChanged();\n        } else {\n          entryBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserSettingEntry.Builder getEntryBuilder(\n          int index) {\n        return getEntryFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserSettingEntryOrBuilder getEntryOrBuilder(\n          int index) {\n        if (entryBuilder_ == null) {\n          return entry_.get(index);  } else {\n          return entryBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.UserSettingEntryOrBuilder> \n           getEntryOrBuilderList() {\n        if (entryBuilder_ != null) {\n          return entryBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(entry_);\n        }\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserSettingEntry.Builder addEntryBuilder() {\n        return getEntryFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.UserSettingEntry.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserSettingEntry.Builder addEntryBuilder(\n          int index) {\n        return getEntryFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.UserSettingEntry.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .UserSettingEntry entry = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.UserSettingEntry.Builder> \n           getEntryBuilderList() {\n        return getEntryFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.UserSettingEntry, cn.wildfirechat.proto.WFCMessage.UserSettingEntry.Builder, cn.wildfirechat.proto.WFCMessage.UserSettingEntryOrBuilder> \n          getEntryFieldBuilder() {\n        if (entryBuilder_ == null) {\n          entryBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.UserSettingEntry, cn.wildfirechat.proto.WFCMessage.UserSettingEntry.Builder, cn.wildfirechat.proto.WFCMessage.UserSettingEntryOrBuilder>(\n                  entry_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          entry_ = null;\n        }\n        return entryBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:GetUserSettingResult)\n    }\n\n    static {\n      defaultInstance = new GetUserSettingResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:GetUserSettingResult)\n  }\n\n  public interface FriendOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string uid = 1;\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    boolean hasUid();\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    java.lang.String getUid();\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getUidBytes();\n\n    // required int32 state = 2;\n    /**\n     * <code>required int32 state = 2;</code>\n     */\n    boolean hasState();\n    /**\n     * <code>required int32 state = 2;</code>\n     */\n    int getState();\n\n    // required int64 update_dt = 3;\n    /**\n     * <code>required int64 update_dt = 3;</code>\n     */\n    boolean hasUpdateDt();\n    /**\n     * <code>required int64 update_dt = 3;</code>\n     */\n    long getUpdateDt();\n\n    // optional string alias = 4;\n    /**\n     * <code>optional string alias = 4;</code>\n     */\n    boolean hasAlias();\n    /**\n     * <code>optional string alias = 4;</code>\n     */\n    java.lang.String getAlias();\n    /**\n     * <code>optional string alias = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getAliasBytes();\n\n    // optional int32 blacked = 5;\n    /**\n     * <code>optional int32 blacked = 5;</code>\n     */\n    boolean hasBlacked();\n    /**\n     * <code>optional int32 blacked = 5;</code>\n     */\n    int getBlacked();\n\n    // optional string extra = 6;\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n  }\n  /**\n   * Protobuf type {@code Friend}\n   */\n  public static final class Friend extends\n      com.google.protobuf.GeneratedMessage\n      implements FriendOrBuilder {\n    // Use Friend.newBuilder() to construct.\n    private Friend(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private Friend(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final Friend defaultInstance;\n    public static Friend getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public Friend getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private Friend(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              uid_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              state_ = input.readInt32();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              updateDt_ = input.readInt64();\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000008;\n              alias_ = input.readBytes();\n              break;\n            }\n            case 40: {\n              bitField0_ |= 0x00000010;\n              blacked_ = input.readInt32();\n              break;\n            }\n            case 50: {\n              bitField0_ |= 0x00000020;\n              extra_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_Friend_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_Friend_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.Friend.class, cn.wildfirechat.proto.WFCMessage.Friend.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<Friend> PARSER =\n        new com.google.protobuf.AbstractParser<Friend>() {\n      public Friend parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new Friend(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<Friend> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string uid = 1;\n    public static final int UID_FIELD_NUMBER = 1;\n    private java.lang.Object uid_;\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public boolean hasUid() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public java.lang.String getUid() {\n      java.lang.Object ref = uid_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          uid_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getUidBytes() {\n      java.lang.Object ref = uid_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        uid_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 state = 2;\n    public static final int STATE_FIELD_NUMBER = 2;\n    private int state_;\n    /**\n     * <code>required int32 state = 2;</code>\n     */\n    public boolean hasState() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 state = 2;</code>\n     */\n    public int getState() {\n      return state_;\n    }\n\n    // required int64 update_dt = 3;\n    public static final int UPDATE_DT_FIELD_NUMBER = 3;\n    private long updateDt_;\n    /**\n     * <code>required int64 update_dt = 3;</code>\n     */\n    public boolean hasUpdateDt() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required int64 update_dt = 3;</code>\n     */\n    public long getUpdateDt() {\n      return updateDt_;\n    }\n\n    // optional string alias = 4;\n    public static final int ALIAS_FIELD_NUMBER = 4;\n    private java.lang.Object alias_;\n    /**\n     * <code>optional string alias = 4;</code>\n     */\n    public boolean hasAlias() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional string alias = 4;</code>\n     */\n    public java.lang.String getAlias() {\n      java.lang.Object ref = alias_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          alias_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string alias = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getAliasBytes() {\n      java.lang.Object ref = alias_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        alias_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 blacked = 5;\n    public static final int BLACKED_FIELD_NUMBER = 5;\n    private int blacked_;\n    /**\n     * <code>optional int32 blacked = 5;</code>\n     */\n    public boolean hasBlacked() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional int32 blacked = 5;</code>\n     */\n    public int getBlacked() {\n      return blacked_;\n    }\n\n    // optional string extra = 6;\n    public static final int EXTRA_FIELD_NUMBER = 6;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 6;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      uid_ = \"\";\n      state_ = 0;\n      updateDt_ = 0L;\n      alias_ = \"\";\n      blacked_ = 0;\n      extra_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasUid()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasState()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasUpdateDt()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, state_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt64(3, updateDt_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(4, getAliasBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeInt32(5, blacked_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeBytes(6, getExtraBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, state_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(3, updateDt_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, getAliasBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(5, blacked_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(6, getExtraBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.Friend parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Friend parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Friend parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Friend parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Friend parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Friend parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Friend parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Friend parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Friend parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.Friend parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.Friend prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code Friend}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.FriendOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Friend_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Friend_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.Friend.class, cn.wildfirechat.proto.WFCMessage.Friend.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.Friend.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        uid_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        state_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        updateDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        alias_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        blacked_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000010);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000020);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_Friend_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Friend getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.Friend.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Friend build() {\n        cn.wildfirechat.proto.WFCMessage.Friend result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.Friend buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.Friend result = new cn.wildfirechat.proto.WFCMessage.Friend(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.uid_ = uid_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.state_ = state_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.updateDt_ = updateDt_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.alias_ = alias_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.blacked_ = blacked_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.extra_ = extra_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.Friend) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.Friend)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.Friend other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.Friend.getDefaultInstance()) return this;\n        if (other.hasUid()) {\n          bitField0_ |= 0x00000001;\n          uid_ = other.uid_;\n          onChanged();\n        }\n        if (other.hasState()) {\n          setState(other.getState());\n        }\n        if (other.hasUpdateDt()) {\n          setUpdateDt(other.getUpdateDt());\n        }\n        if (other.hasAlias()) {\n          bitField0_ |= 0x00000008;\n          alias_ = other.alias_;\n          onChanged();\n        }\n        if (other.hasBlacked()) {\n          setBlacked(other.getBlacked());\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000020;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasUid()) {\n          \n          return false;\n        }\n        if (!hasState()) {\n          \n          return false;\n        }\n        if (!hasUpdateDt()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.Friend parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.Friend) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string uid = 1;\n      private java.lang.Object uid_ = \"\";\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public boolean hasUid() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public java.lang.String getUid() {\n        java.lang.Object ref = uid_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          uid_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getUidBytes() {\n        java.lang.Object ref = uid_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          uid_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder setUid(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        uid_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder clearUid() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        uid_ = getDefaultInstance().getUid();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder setUidBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        uid_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 state = 2;\n      private int state_ ;\n      /**\n       * <code>required int32 state = 2;</code>\n       */\n      public boolean hasState() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 state = 2;</code>\n       */\n      public int getState() {\n        return state_;\n      }\n      /**\n       * <code>required int32 state = 2;</code>\n       */\n      public Builder setState(int value) {\n        bitField0_ |= 0x00000002;\n        state_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 state = 2;</code>\n       */\n      public Builder clearState() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        state_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required int64 update_dt = 3;\n      private long updateDt_ ;\n      /**\n       * <code>required int64 update_dt = 3;</code>\n       */\n      public boolean hasUpdateDt() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required int64 update_dt = 3;</code>\n       */\n      public long getUpdateDt() {\n        return updateDt_;\n      }\n      /**\n       * <code>required int64 update_dt = 3;</code>\n       */\n      public Builder setUpdateDt(long value) {\n        bitField0_ |= 0x00000004;\n        updateDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 update_dt = 3;</code>\n       */\n      public Builder clearUpdateDt() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        updateDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional string alias = 4;\n      private java.lang.Object alias_ = \"\";\n      /**\n       * <code>optional string alias = 4;</code>\n       */\n      public boolean hasAlias() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional string alias = 4;</code>\n       */\n      public java.lang.String getAlias() {\n        java.lang.Object ref = alias_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          alias_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string alias = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getAliasBytes() {\n        java.lang.Object ref = alias_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          alias_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string alias = 4;</code>\n       */\n      public Builder setAlias(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        alias_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string alias = 4;</code>\n       */\n      public Builder clearAlias() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        alias_ = getDefaultInstance().getAlias();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string alias = 4;</code>\n       */\n      public Builder setAliasBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        alias_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 blacked = 5;\n      private int blacked_ ;\n      /**\n       * <code>optional int32 blacked = 5;</code>\n       */\n      public boolean hasBlacked() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional int32 blacked = 5;</code>\n       */\n      public int getBlacked() {\n        return blacked_;\n      }\n      /**\n       * <code>optional int32 blacked = 5;</code>\n       */\n      public Builder setBlacked(int value) {\n        bitField0_ |= 0x00000010;\n        blacked_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 blacked = 5;</code>\n       */\n      public Builder clearBlacked() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        blacked_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional string extra = 6;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 6;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:Friend)\n    }\n\n    static {\n      defaultInstance = new Friend(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:Friend)\n  }\n\n  public interface GetFriendsResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .Friend entry = 1;\n    /**\n     * <code>repeated .Friend entry = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.Friend> \n        getEntryList();\n    /**\n     * <code>repeated .Friend entry = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.Friend getEntry(int index);\n    /**\n     * <code>repeated .Friend entry = 1;</code>\n     */\n    int getEntryCount();\n    /**\n     * <code>repeated .Friend entry = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.FriendOrBuilder> \n        getEntryOrBuilderList();\n    /**\n     * <code>repeated .Friend entry = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.FriendOrBuilder getEntryOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code GetFriendsResult}\n   */\n  public static final class GetFriendsResult extends\n      com.google.protobuf.GeneratedMessage\n      implements GetFriendsResultOrBuilder {\n    // Use GetFriendsResult.newBuilder() to construct.\n    private GetFriendsResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private GetFriendsResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final GetFriendsResult defaultInstance;\n    public static GetFriendsResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public GetFriendsResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private GetFriendsResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                entry_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.Friend>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              entry_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.Friend.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          entry_ = java.util.Collections.unmodifiableList(entry_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetFriendsResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetFriendsResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.GetFriendsResult.class, cn.wildfirechat.proto.WFCMessage.GetFriendsResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<GetFriendsResult> PARSER =\n        new com.google.protobuf.AbstractParser<GetFriendsResult>() {\n      public GetFriendsResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new GetFriendsResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<GetFriendsResult> getParserForType() {\n      return PARSER;\n    }\n\n    // repeated .Friend entry = 1;\n    public static final int ENTRY_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.Friend> entry_;\n    /**\n     * <code>repeated .Friend entry = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.Friend> getEntryList() {\n      return entry_;\n    }\n    /**\n     * <code>repeated .Friend entry = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.FriendOrBuilder> \n        getEntryOrBuilderList() {\n      return entry_;\n    }\n    /**\n     * <code>repeated .Friend entry = 1;</code>\n     */\n    public int getEntryCount() {\n      return entry_.size();\n    }\n    /**\n     * <code>repeated .Friend entry = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.Friend getEntry(int index) {\n      return entry_.get(index);\n    }\n    /**\n     * <code>repeated .Friend entry = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.FriendOrBuilder getEntryOrBuilder(\n        int index) {\n      return entry_.get(index);\n    }\n\n    private void initFields() {\n      entry_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      for (int i = 0; i < getEntryCount(); i++) {\n        if (!getEntry(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < entry_.size(); i++) {\n        output.writeMessage(1, entry_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < entry_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, entry_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendsResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendsResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendsResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendsResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendsResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendsResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendsResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendsResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendsResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendsResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.GetFriendsResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code GetFriendsResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GetFriendsResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetFriendsResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetFriendsResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.GetFriendsResult.class, cn.wildfirechat.proto.WFCMessage.GetFriendsResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.GetFriendsResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getEntryFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (entryBuilder_ == null) {\n          entry_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          entryBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetFriendsResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetFriendsResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.GetFriendsResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetFriendsResult build() {\n        cn.wildfirechat.proto.WFCMessage.GetFriendsResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetFriendsResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.GetFriendsResult result = new cn.wildfirechat.proto.WFCMessage.GetFriendsResult(this);\n        int from_bitField0_ = bitField0_;\n        if (entryBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            entry_ = java.util.Collections.unmodifiableList(entry_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.entry_ = entry_;\n        } else {\n          result.entry_ = entryBuilder_.build();\n        }\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.GetFriendsResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.GetFriendsResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.GetFriendsResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.GetFriendsResult.getDefaultInstance()) return this;\n        if (entryBuilder_ == null) {\n          if (!other.entry_.isEmpty()) {\n            if (entry_.isEmpty()) {\n              entry_ = other.entry_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureEntryIsMutable();\n              entry_.addAll(other.entry_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.entry_.isEmpty()) {\n            if (entryBuilder_.isEmpty()) {\n              entryBuilder_.dispose();\n              entryBuilder_ = null;\n              entry_ = other.entry_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              entryBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getEntryFieldBuilder() : null;\n            } else {\n              entryBuilder_.addAllMessages(other.entry_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        for (int i = 0; i < getEntryCount(); i++) {\n          if (!getEntry(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.GetFriendsResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.GetFriendsResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .Friend entry = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.Friend> entry_ =\n        java.util.Collections.emptyList();\n      private void ensureEntryIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          entry_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.Friend>(entry_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.Friend, cn.wildfirechat.proto.WFCMessage.Friend.Builder, cn.wildfirechat.proto.WFCMessage.FriendOrBuilder> entryBuilder_;\n\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.Friend> getEntryList() {\n        if (entryBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(entry_);\n        } else {\n          return entryBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public int getEntryCount() {\n        if (entryBuilder_ == null) {\n          return entry_.size();\n        } else {\n          return entryBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Friend getEntry(int index) {\n        if (entryBuilder_ == null) {\n          return entry_.get(index);\n        } else {\n          return entryBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public Builder setEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.Friend value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.set(index, value);\n          onChanged();\n        } else {\n          entryBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public Builder setEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.Friend.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public Builder addEntry(cn.wildfirechat.proto.WFCMessage.Friend value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.add(value);\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public Builder addEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.Friend value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.add(index, value);\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public Builder addEntry(\n          cn.wildfirechat.proto.WFCMessage.Friend.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.add(builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public Builder addEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.Friend.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public Builder addAllEntry(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.Friend> values) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          super.addAll(values, entry_);\n          onChanged();\n        } else {\n          entryBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public Builder clearEntry() {\n        if (entryBuilder_ == null) {\n          entry_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          entryBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public Builder removeEntry(int index) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.remove(index);\n          onChanged();\n        } else {\n          entryBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Friend.Builder getEntryBuilder(\n          int index) {\n        return getEntryFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.FriendOrBuilder getEntryOrBuilder(\n          int index) {\n        if (entryBuilder_ == null) {\n          return entry_.get(index);  } else {\n          return entryBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.FriendOrBuilder> \n           getEntryOrBuilderList() {\n        if (entryBuilder_ != null) {\n          return entryBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(entry_);\n        }\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Friend.Builder addEntryBuilder() {\n        return getEntryFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.Friend.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Friend.Builder addEntryBuilder(\n          int index) {\n        return getEntryFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.Friend.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .Friend entry = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.Friend.Builder> \n           getEntryBuilderList() {\n        return getEntryFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.Friend, cn.wildfirechat.proto.WFCMessage.Friend.Builder, cn.wildfirechat.proto.WFCMessage.FriendOrBuilder> \n          getEntryFieldBuilder() {\n        if (entryBuilder_ == null) {\n          entryBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.Friend, cn.wildfirechat.proto.WFCMessage.Friend.Builder, cn.wildfirechat.proto.WFCMessage.FriendOrBuilder>(\n                  entry_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          entry_ = null;\n        }\n        return entryBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:GetFriendsResult)\n    }\n\n    static {\n      defaultInstance = new GetFriendsResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:GetFriendsResult)\n  }\n\n  public interface GetFriendRequestResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .FriendRequest entry = 1;\n    /**\n     * <code>repeated .FriendRequest entry = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.FriendRequest> \n        getEntryList();\n    /**\n     * <code>repeated .FriendRequest entry = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.FriendRequest getEntry(int index);\n    /**\n     * <code>repeated .FriendRequest entry = 1;</code>\n     */\n    int getEntryCount();\n    /**\n     * <code>repeated .FriendRequest entry = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.FriendRequestOrBuilder> \n        getEntryOrBuilderList();\n    /**\n     * <code>repeated .FriendRequest entry = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.FriendRequestOrBuilder getEntryOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code GetFriendRequestResult}\n   */\n  public static final class GetFriendRequestResult extends\n      com.google.protobuf.GeneratedMessage\n      implements GetFriendRequestResultOrBuilder {\n    // Use GetFriendRequestResult.newBuilder() to construct.\n    private GetFriendRequestResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private GetFriendRequestResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final GetFriendRequestResult defaultInstance;\n    public static GetFriendRequestResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public GetFriendRequestResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private GetFriendRequestResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                entry_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.FriendRequest>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              entry_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.FriendRequest.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          entry_ = java.util.Collections.unmodifiableList(entry_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetFriendRequestResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetFriendRequestResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult.class, cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<GetFriendRequestResult> PARSER =\n        new com.google.protobuf.AbstractParser<GetFriendRequestResult>() {\n      public GetFriendRequestResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new GetFriendRequestResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<GetFriendRequestResult> getParserForType() {\n      return PARSER;\n    }\n\n    // repeated .FriendRequest entry = 1;\n    public static final int ENTRY_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.FriendRequest> entry_;\n    /**\n     * <code>repeated .FriendRequest entry = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.FriendRequest> getEntryList() {\n      return entry_;\n    }\n    /**\n     * <code>repeated .FriendRequest entry = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.FriendRequestOrBuilder> \n        getEntryOrBuilderList() {\n      return entry_;\n    }\n    /**\n     * <code>repeated .FriendRequest entry = 1;</code>\n     */\n    public int getEntryCount() {\n      return entry_.size();\n    }\n    /**\n     * <code>repeated .FriendRequest entry = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.FriendRequest getEntry(int index) {\n      return entry_.get(index);\n    }\n    /**\n     * <code>repeated .FriendRequest entry = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.FriendRequestOrBuilder getEntryOrBuilder(\n        int index) {\n      return entry_.get(index);\n    }\n\n    private void initFields() {\n      entry_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      for (int i = 0; i < getEntryCount(); i++) {\n        if (!getEntry(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < entry_.size(); i++) {\n        output.writeMessage(1, entry_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < entry_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, entry_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code GetFriendRequestResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GetFriendRequestResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetFriendRequestResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetFriendRequestResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult.class, cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getEntryFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (entryBuilder_ == null) {\n          entry_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          entryBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetFriendRequestResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult build() {\n        cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult result = new cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult(this);\n        int from_bitField0_ = bitField0_;\n        if (entryBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            entry_ = java.util.Collections.unmodifiableList(entry_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.entry_ = entry_;\n        } else {\n          result.entry_ = entryBuilder_.build();\n        }\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult.getDefaultInstance()) return this;\n        if (entryBuilder_ == null) {\n          if (!other.entry_.isEmpty()) {\n            if (entry_.isEmpty()) {\n              entry_ = other.entry_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureEntryIsMutable();\n              entry_.addAll(other.entry_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.entry_.isEmpty()) {\n            if (entryBuilder_.isEmpty()) {\n              entryBuilder_.dispose();\n              entryBuilder_ = null;\n              entry_ = other.entry_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              entryBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getEntryFieldBuilder() : null;\n            } else {\n              entryBuilder_.addAllMessages(other.entry_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        for (int i = 0; i < getEntryCount(); i++) {\n          if (!getEntry(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.GetFriendRequestResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .FriendRequest entry = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.FriendRequest> entry_ =\n        java.util.Collections.emptyList();\n      private void ensureEntryIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          entry_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.FriendRequest>(entry_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.FriendRequest, cn.wildfirechat.proto.WFCMessage.FriendRequest.Builder, cn.wildfirechat.proto.WFCMessage.FriendRequestOrBuilder> entryBuilder_;\n\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.FriendRequest> getEntryList() {\n        if (entryBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(entry_);\n        } else {\n          return entryBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public int getEntryCount() {\n        if (entryBuilder_ == null) {\n          return entry_.size();\n        } else {\n          return entryBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.FriendRequest getEntry(int index) {\n        if (entryBuilder_ == null) {\n          return entry_.get(index);\n        } else {\n          return entryBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public Builder setEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.FriendRequest value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.set(index, value);\n          onChanged();\n        } else {\n          entryBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public Builder setEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.FriendRequest.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public Builder addEntry(cn.wildfirechat.proto.WFCMessage.FriendRequest value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.add(value);\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public Builder addEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.FriendRequest value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.add(index, value);\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public Builder addEntry(\n          cn.wildfirechat.proto.WFCMessage.FriendRequest.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.add(builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public Builder addEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.FriendRequest.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public Builder addAllEntry(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.FriendRequest> values) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          super.addAll(values, entry_);\n          onChanged();\n        } else {\n          entryBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public Builder clearEntry() {\n        if (entryBuilder_ == null) {\n          entry_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          entryBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public Builder removeEntry(int index) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.remove(index);\n          onChanged();\n        } else {\n          entryBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.FriendRequest.Builder getEntryBuilder(\n          int index) {\n        return getEntryFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.FriendRequestOrBuilder getEntryOrBuilder(\n          int index) {\n        if (entryBuilder_ == null) {\n          return entry_.get(index);  } else {\n          return entryBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.FriendRequestOrBuilder> \n           getEntryOrBuilderList() {\n        if (entryBuilder_ != null) {\n          return entryBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(entry_);\n        }\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.FriendRequest.Builder addEntryBuilder() {\n        return getEntryFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.FriendRequest.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.FriendRequest.Builder addEntryBuilder(\n          int index) {\n        return getEntryFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.FriendRequest.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .FriendRequest entry = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.FriendRequest.Builder> \n           getEntryBuilderList() {\n        return getEntryFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.FriendRequest, cn.wildfirechat.proto.WFCMessage.FriendRequest.Builder, cn.wildfirechat.proto.WFCMessage.FriendRequestOrBuilder> \n          getEntryFieldBuilder() {\n        if (entryBuilder_ == null) {\n          entryBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.FriendRequest, cn.wildfirechat.proto.WFCMessage.FriendRequest.Builder, cn.wildfirechat.proto.WFCMessage.FriendRequestOrBuilder>(\n                  entry_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          entry_ = null;\n        }\n        return entryBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:GetFriendRequestResult)\n    }\n\n    static {\n      defaultInstance = new GetFriendRequestResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:GetFriendRequestResult)\n  }\n\n  public interface ConnectAckPayloadOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // optional int64 msg_head = 1;\n    /**\n     * <code>optional int64 msg_head = 1;</code>\n     */\n    boolean hasMsgHead();\n    /**\n     * <code>optional int64 msg_head = 1;</code>\n     */\n    long getMsgHead();\n\n    // optional int64 friend_head = 2;\n    /**\n     * <code>optional int64 friend_head = 2;</code>\n     */\n    boolean hasFriendHead();\n    /**\n     * <code>optional int64 friend_head = 2;</code>\n     */\n    long getFriendHead();\n\n    // optional int64 friend_rq_head = 3;\n    /**\n     * <code>optional int64 friend_rq_head = 3;</code>\n     */\n    boolean hasFriendRqHead();\n    /**\n     * <code>optional int64 friend_rq_head = 3;</code>\n     */\n    long getFriendRqHead();\n\n    // optional int64 setting_head = 4;\n    /**\n     * <code>optional int64 setting_head = 4;</code>\n     */\n    boolean hasSettingHead();\n    /**\n     * <code>optional int64 setting_head = 4;</code>\n     */\n    long getSettingHead();\n\n    // optional string node_addr = 5;\n    /**\n     * <code>optional string node_addr = 5;</code>\n     */\n    boolean hasNodeAddr();\n    /**\n     * <code>optional string node_addr = 5;</code>\n     */\n    java.lang.String getNodeAddr();\n    /**\n     * <code>optional string node_addr = 5;</code>\n     */\n    com.google.protobuf.ByteString\n        getNodeAddrBytes();\n\n    // optional int32 node_port = 6;\n    /**\n     * <code>optional int32 node_port = 6;</code>\n     */\n    boolean hasNodePort();\n    /**\n     * <code>optional int32 node_port = 6;</code>\n     */\n    int getNodePort();\n\n    // optional int64 server_time = 7;\n    /**\n     * <code>optional int64 server_time = 7;</code>\n     */\n    boolean hasServerTime();\n    /**\n     * <code>optional int64 server_time = 7;</code>\n     */\n    long getServerTime();\n  }\n  /**\n   * Protobuf type {@code ConnectAckPayload}\n   */\n  public static final class ConnectAckPayload extends\n      com.google.protobuf.GeneratedMessage\n      implements ConnectAckPayloadOrBuilder {\n    // Use ConnectAckPayload.newBuilder() to construct.\n    private ConnectAckPayload(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ConnectAckPayload(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ConnectAckPayload defaultInstance;\n    public static ConnectAckPayload getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ConnectAckPayload getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ConnectAckPayload(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              msgHead_ = input.readInt64();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              friendHead_ = input.readInt64();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              friendRqHead_ = input.readInt64();\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000008;\n              settingHead_ = input.readInt64();\n              break;\n            }\n            case 42: {\n              bitField0_ |= 0x00000010;\n              nodeAddr_ = input.readBytes();\n              break;\n            }\n            case 48: {\n              bitField0_ |= 0x00000020;\n              nodePort_ = input.readInt32();\n              break;\n            }\n            case 56: {\n              bitField0_ |= 0x00000040;\n              serverTime_ = input.readInt64();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ConnectAckPayload_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ConnectAckPayload_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ConnectAckPayload.class, cn.wildfirechat.proto.WFCMessage.ConnectAckPayload.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ConnectAckPayload> PARSER =\n        new com.google.protobuf.AbstractParser<ConnectAckPayload>() {\n      public ConnectAckPayload parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ConnectAckPayload(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ConnectAckPayload> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // optional int64 msg_head = 1;\n    public static final int MSG_HEAD_FIELD_NUMBER = 1;\n    private long msgHead_;\n    /**\n     * <code>optional int64 msg_head = 1;</code>\n     */\n    public boolean hasMsgHead() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional int64 msg_head = 1;</code>\n     */\n    public long getMsgHead() {\n      return msgHead_;\n    }\n\n    // optional int64 friend_head = 2;\n    public static final int FRIEND_HEAD_FIELD_NUMBER = 2;\n    private long friendHead_;\n    /**\n     * <code>optional int64 friend_head = 2;</code>\n     */\n    public boolean hasFriendHead() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional int64 friend_head = 2;</code>\n     */\n    public long getFriendHead() {\n      return friendHead_;\n    }\n\n    // optional int64 friend_rq_head = 3;\n    public static final int FRIEND_RQ_HEAD_FIELD_NUMBER = 3;\n    private long friendRqHead_;\n    /**\n     * <code>optional int64 friend_rq_head = 3;</code>\n     */\n    public boolean hasFriendRqHead() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional int64 friend_rq_head = 3;</code>\n     */\n    public long getFriendRqHead() {\n      return friendRqHead_;\n    }\n\n    // optional int64 setting_head = 4;\n    public static final int SETTING_HEAD_FIELD_NUMBER = 4;\n    private long settingHead_;\n    /**\n     * <code>optional int64 setting_head = 4;</code>\n     */\n    public boolean hasSettingHead() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional int64 setting_head = 4;</code>\n     */\n    public long getSettingHead() {\n      return settingHead_;\n    }\n\n    // optional string node_addr = 5;\n    public static final int NODE_ADDR_FIELD_NUMBER = 5;\n    private java.lang.Object nodeAddr_;\n    /**\n     * <code>optional string node_addr = 5;</code>\n     */\n    public boolean hasNodeAddr() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional string node_addr = 5;</code>\n     */\n    public java.lang.String getNodeAddr() {\n      java.lang.Object ref = nodeAddr_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          nodeAddr_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string node_addr = 5;</code>\n     */\n    public com.google.protobuf.ByteString\n        getNodeAddrBytes() {\n      java.lang.Object ref = nodeAddr_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        nodeAddr_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 node_port = 6;\n    public static final int NODE_PORT_FIELD_NUMBER = 6;\n    private int nodePort_;\n    /**\n     * <code>optional int32 node_port = 6;</code>\n     */\n    public boolean hasNodePort() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional int32 node_port = 6;</code>\n     */\n    public int getNodePort() {\n      return nodePort_;\n    }\n\n    // optional int64 server_time = 7;\n    public static final int SERVER_TIME_FIELD_NUMBER = 7;\n    private long serverTime_;\n    /**\n     * <code>optional int64 server_time = 7;</code>\n     */\n    public boolean hasServerTime() {\n      return ((bitField0_ & 0x00000040) == 0x00000040);\n    }\n    /**\n     * <code>optional int64 server_time = 7;</code>\n     */\n    public long getServerTime() {\n      return serverTime_;\n    }\n\n    private void initFields() {\n      msgHead_ = 0L;\n      friendHead_ = 0L;\n      friendRqHead_ = 0L;\n      settingHead_ = 0L;\n      nodeAddr_ = \"\";\n      nodePort_ = 0;\n      serverTime_ = 0L;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt64(1, msgHead_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt64(2, friendHead_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt64(3, friendRqHead_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeInt64(4, settingHead_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeBytes(5, getNodeAddrBytes());\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeInt32(6, nodePort_);\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        output.writeInt64(7, serverTime_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, msgHead_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(2, friendHead_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(3, friendRqHead_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(4, settingHead_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5, getNodeAddrBytes());\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(6, nodePort_);\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(7, serverTime_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ConnectAckPayload parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ConnectAckPayload parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ConnectAckPayload parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ConnectAckPayload parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ConnectAckPayload parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ConnectAckPayload parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ConnectAckPayload parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ConnectAckPayload parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ConnectAckPayload parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ConnectAckPayload parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ConnectAckPayload prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ConnectAckPayload}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ConnectAckPayloadOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ConnectAckPayload_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ConnectAckPayload_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ConnectAckPayload.class, cn.wildfirechat.proto.WFCMessage.ConnectAckPayload.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ConnectAckPayload.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        msgHead_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        friendHead_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        friendRqHead_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        settingHead_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        nodeAddr_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000010);\n        nodePort_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000020);\n        serverTime_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000040);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ConnectAckPayload_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ConnectAckPayload getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ConnectAckPayload.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ConnectAckPayload build() {\n        cn.wildfirechat.proto.WFCMessage.ConnectAckPayload result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ConnectAckPayload buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ConnectAckPayload result = new cn.wildfirechat.proto.WFCMessage.ConnectAckPayload(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.msgHead_ = msgHead_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.friendHead_ = friendHead_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.friendRqHead_ = friendRqHead_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.settingHead_ = settingHead_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.nodeAddr_ = nodeAddr_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.nodePort_ = nodePort_;\n        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {\n          to_bitField0_ |= 0x00000040;\n        }\n        result.serverTime_ = serverTime_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ConnectAckPayload) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ConnectAckPayload)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ConnectAckPayload other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ConnectAckPayload.getDefaultInstance()) return this;\n        if (other.hasMsgHead()) {\n          setMsgHead(other.getMsgHead());\n        }\n        if (other.hasFriendHead()) {\n          setFriendHead(other.getFriendHead());\n        }\n        if (other.hasFriendRqHead()) {\n          setFriendRqHead(other.getFriendRqHead());\n        }\n        if (other.hasSettingHead()) {\n          setSettingHead(other.getSettingHead());\n        }\n        if (other.hasNodeAddr()) {\n          bitField0_ |= 0x00000010;\n          nodeAddr_ = other.nodeAddr_;\n          onChanged();\n        }\n        if (other.hasNodePort()) {\n          setNodePort(other.getNodePort());\n        }\n        if (other.hasServerTime()) {\n          setServerTime(other.getServerTime());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ConnectAckPayload parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ConnectAckPayload) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // optional int64 msg_head = 1;\n      private long msgHead_ ;\n      /**\n       * <code>optional int64 msg_head = 1;</code>\n       */\n      public boolean hasMsgHead() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional int64 msg_head = 1;</code>\n       */\n      public long getMsgHead() {\n        return msgHead_;\n      }\n      /**\n       * <code>optional int64 msg_head = 1;</code>\n       */\n      public Builder setMsgHead(long value) {\n        bitField0_ |= 0x00000001;\n        msgHead_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 msg_head = 1;</code>\n       */\n      public Builder clearMsgHead() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        msgHead_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 friend_head = 2;\n      private long friendHead_ ;\n      /**\n       * <code>optional int64 friend_head = 2;</code>\n       */\n      public boolean hasFriendHead() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional int64 friend_head = 2;</code>\n       */\n      public long getFriendHead() {\n        return friendHead_;\n      }\n      /**\n       * <code>optional int64 friend_head = 2;</code>\n       */\n      public Builder setFriendHead(long value) {\n        bitField0_ |= 0x00000002;\n        friendHead_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 friend_head = 2;</code>\n       */\n      public Builder clearFriendHead() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        friendHead_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 friend_rq_head = 3;\n      private long friendRqHead_ ;\n      /**\n       * <code>optional int64 friend_rq_head = 3;</code>\n       */\n      public boolean hasFriendRqHead() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional int64 friend_rq_head = 3;</code>\n       */\n      public long getFriendRqHead() {\n        return friendRqHead_;\n      }\n      /**\n       * <code>optional int64 friend_rq_head = 3;</code>\n       */\n      public Builder setFriendRqHead(long value) {\n        bitField0_ |= 0x00000004;\n        friendRqHead_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 friend_rq_head = 3;</code>\n       */\n      public Builder clearFriendRqHead() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        friendRqHead_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 setting_head = 4;\n      private long settingHead_ ;\n      /**\n       * <code>optional int64 setting_head = 4;</code>\n       */\n      public boolean hasSettingHead() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional int64 setting_head = 4;</code>\n       */\n      public long getSettingHead() {\n        return settingHead_;\n      }\n      /**\n       * <code>optional int64 setting_head = 4;</code>\n       */\n      public Builder setSettingHead(long value) {\n        bitField0_ |= 0x00000008;\n        settingHead_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 setting_head = 4;</code>\n       */\n      public Builder clearSettingHead() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        settingHead_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional string node_addr = 5;\n      private java.lang.Object nodeAddr_ = \"\";\n      /**\n       * <code>optional string node_addr = 5;</code>\n       */\n      public boolean hasNodeAddr() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional string node_addr = 5;</code>\n       */\n      public java.lang.String getNodeAddr() {\n        java.lang.Object ref = nodeAddr_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          nodeAddr_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string node_addr = 5;</code>\n       */\n      public com.google.protobuf.ByteString\n          getNodeAddrBytes() {\n        java.lang.Object ref = nodeAddr_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          nodeAddr_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string node_addr = 5;</code>\n       */\n      public Builder setNodeAddr(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        nodeAddr_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string node_addr = 5;</code>\n       */\n      public Builder clearNodeAddr() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        nodeAddr_ = getDefaultInstance().getNodeAddr();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string node_addr = 5;</code>\n       */\n      public Builder setNodeAddrBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        nodeAddr_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 node_port = 6;\n      private int nodePort_ ;\n      /**\n       * <code>optional int32 node_port = 6;</code>\n       */\n      public boolean hasNodePort() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional int32 node_port = 6;</code>\n       */\n      public int getNodePort() {\n        return nodePort_;\n      }\n      /**\n       * <code>optional int32 node_port = 6;</code>\n       */\n      public Builder setNodePort(int value) {\n        bitField0_ |= 0x00000020;\n        nodePort_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 node_port = 6;</code>\n       */\n      public Builder clearNodePort() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        nodePort_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 server_time = 7;\n      private long serverTime_ ;\n      /**\n       * <code>optional int64 server_time = 7;</code>\n       */\n      public boolean hasServerTime() {\n        return ((bitField0_ & 0x00000040) == 0x00000040);\n      }\n      /**\n       * <code>optional int64 server_time = 7;</code>\n       */\n      public long getServerTime() {\n        return serverTime_;\n      }\n      /**\n       * <code>optional int64 server_time = 7;</code>\n       */\n      public Builder setServerTime(long value) {\n        bitField0_ |= 0x00000040;\n        serverTime_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 server_time = 7;</code>\n       */\n      public Builder clearServerTime() {\n        bitField0_ = (bitField0_ & ~0x00000040);\n        serverTime_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ConnectAckPayload)\n    }\n\n    static {\n      defaultInstance = new ConnectAckPayload(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ConnectAckPayload)\n  }\n\n  public interface IMHttpWrapperOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string token = 1;\n    /**\n     * <code>required string token = 1;</code>\n     */\n    boolean hasToken();\n    /**\n     * <code>required string token = 1;</code>\n     */\n    java.lang.String getToken();\n    /**\n     * <code>required string token = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getTokenBytes();\n\n    // required string client_id = 2;\n    /**\n     * <code>required string client_id = 2;</code>\n     */\n    boolean hasClientId();\n    /**\n     * <code>required string client_id = 2;</code>\n     */\n    java.lang.String getClientId();\n    /**\n     * <code>required string client_id = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getClientIdBytes();\n\n    // required string request = 3;\n    /**\n     * <code>required string request = 3;</code>\n     */\n    boolean hasRequest();\n    /**\n     * <code>required string request = 3;</code>\n     */\n    java.lang.String getRequest();\n    /**\n     * <code>required string request = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getRequestBytes();\n\n    // optional bytes data = 4;\n    /**\n     * <code>optional bytes data = 4;</code>\n     */\n    boolean hasData();\n    /**\n     * <code>optional bytes data = 4;</code>\n     */\n    com.google.protobuf.ByteString getData();\n  }\n  /**\n   * Protobuf type {@code IMHttpWrapper}\n   */\n  public static final class IMHttpWrapper extends\n      com.google.protobuf.GeneratedMessage\n      implements IMHttpWrapperOrBuilder {\n    // Use IMHttpWrapper.newBuilder() to construct.\n    private IMHttpWrapper(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private IMHttpWrapper(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final IMHttpWrapper defaultInstance;\n    public static IMHttpWrapper getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public IMHttpWrapper getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private IMHttpWrapper(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              token_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              clientId_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              request_ = input.readBytes();\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000008;\n              data_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_IMHttpWrapper_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_IMHttpWrapper_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.IMHttpWrapper.class, cn.wildfirechat.proto.WFCMessage.IMHttpWrapper.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<IMHttpWrapper> PARSER =\n        new com.google.protobuf.AbstractParser<IMHttpWrapper>() {\n      public IMHttpWrapper parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new IMHttpWrapper(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<IMHttpWrapper> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string token = 1;\n    public static final int TOKEN_FIELD_NUMBER = 1;\n    private java.lang.Object token_;\n    /**\n     * <code>required string token = 1;</code>\n     */\n    public boolean hasToken() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string token = 1;</code>\n     */\n    public java.lang.String getToken() {\n      java.lang.Object ref = token_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          token_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string token = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTokenBytes() {\n      java.lang.Object ref = token_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        token_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string client_id = 2;\n    public static final int CLIENT_ID_FIELD_NUMBER = 2;\n    private java.lang.Object clientId_;\n    /**\n     * <code>required string client_id = 2;</code>\n     */\n    public boolean hasClientId() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string client_id = 2;</code>\n     */\n    public java.lang.String getClientId() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          clientId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string client_id = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getClientIdBytes() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        clientId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string request = 3;\n    public static final int REQUEST_FIELD_NUMBER = 3;\n    private java.lang.Object request_;\n    /**\n     * <code>required string request = 3;</code>\n     */\n    public boolean hasRequest() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required string request = 3;</code>\n     */\n    public java.lang.String getRequest() {\n      java.lang.Object ref = request_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          request_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string request = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getRequestBytes() {\n      java.lang.Object ref = request_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        request_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional bytes data = 4;\n    public static final int DATA_FIELD_NUMBER = 4;\n    private com.google.protobuf.ByteString data_;\n    /**\n     * <code>optional bytes data = 4;</code>\n     */\n    public boolean hasData() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional bytes data = 4;</code>\n     */\n    public com.google.protobuf.ByteString getData() {\n      return data_;\n    }\n\n    private void initFields() {\n      token_ = \"\";\n      clientId_ = \"\";\n      request_ = \"\";\n      data_ = com.google.protobuf.ByteString.EMPTY;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasToken()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasClientId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasRequest()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getTokenBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getClientIdBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getRequestBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(4, data_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getTokenBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getClientIdBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getRequestBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, data_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.IMHttpWrapper parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IMHttpWrapper parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IMHttpWrapper parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IMHttpWrapper parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IMHttpWrapper parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IMHttpWrapper parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IMHttpWrapper parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IMHttpWrapper parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IMHttpWrapper parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.IMHttpWrapper parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.IMHttpWrapper prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code IMHttpWrapper}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.IMHttpWrapperOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_IMHttpWrapper_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_IMHttpWrapper_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.IMHttpWrapper.class, cn.wildfirechat.proto.WFCMessage.IMHttpWrapper.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.IMHttpWrapper.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        token_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        clientId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        request_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        data_ = com.google.protobuf.ByteString.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_IMHttpWrapper_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.IMHttpWrapper getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.IMHttpWrapper.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.IMHttpWrapper build() {\n        cn.wildfirechat.proto.WFCMessage.IMHttpWrapper result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.IMHttpWrapper buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.IMHttpWrapper result = new cn.wildfirechat.proto.WFCMessage.IMHttpWrapper(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.token_ = token_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.clientId_ = clientId_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.request_ = request_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.data_ = data_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.IMHttpWrapper) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.IMHttpWrapper)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.IMHttpWrapper other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.IMHttpWrapper.getDefaultInstance()) return this;\n        if (other.hasToken()) {\n          bitField0_ |= 0x00000001;\n          token_ = other.token_;\n          onChanged();\n        }\n        if (other.hasClientId()) {\n          bitField0_ |= 0x00000002;\n          clientId_ = other.clientId_;\n          onChanged();\n        }\n        if (other.hasRequest()) {\n          bitField0_ |= 0x00000004;\n          request_ = other.request_;\n          onChanged();\n        }\n        if (other.hasData()) {\n          setData(other.getData());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasToken()) {\n          \n          return false;\n        }\n        if (!hasClientId()) {\n          \n          return false;\n        }\n        if (!hasRequest()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.IMHttpWrapper parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.IMHttpWrapper) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string token = 1;\n      private java.lang.Object token_ = \"\";\n      /**\n       * <code>required string token = 1;</code>\n       */\n      public boolean hasToken() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string token = 1;</code>\n       */\n      public java.lang.String getToken() {\n        java.lang.Object ref = token_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          token_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string token = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTokenBytes() {\n        java.lang.Object ref = token_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          token_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string token = 1;</code>\n       */\n      public Builder setToken(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        token_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string token = 1;</code>\n       */\n      public Builder clearToken() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        token_ = getDefaultInstance().getToken();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string token = 1;</code>\n       */\n      public Builder setTokenBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        token_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string client_id = 2;\n      private java.lang.Object clientId_ = \"\";\n      /**\n       * <code>required string client_id = 2;</code>\n       */\n      public boolean hasClientId() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string client_id = 2;</code>\n       */\n      public java.lang.String getClientId() {\n        java.lang.Object ref = clientId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          clientId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string client_id = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getClientIdBytes() {\n        java.lang.Object ref = clientId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          clientId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string client_id = 2;</code>\n       */\n      public Builder setClientId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string client_id = 2;</code>\n       */\n      public Builder clearClientId() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        clientId_ = getDefaultInstance().getClientId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string client_id = 2;</code>\n       */\n      public Builder setClientIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string request = 3;\n      private java.lang.Object request_ = \"\";\n      /**\n       * <code>required string request = 3;</code>\n       */\n      public boolean hasRequest() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required string request = 3;</code>\n       */\n      public java.lang.String getRequest() {\n        java.lang.Object ref = request_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          request_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string request = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getRequestBytes() {\n        java.lang.Object ref = request_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          request_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string request = 3;</code>\n       */\n      public Builder setRequest(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        request_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string request = 3;</code>\n       */\n      public Builder clearRequest() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        request_ = getDefaultInstance().getRequest();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string request = 3;</code>\n       */\n      public Builder setRequestBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        request_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional bytes data = 4;\n      private com.google.protobuf.ByteString data_ = com.google.protobuf.ByteString.EMPTY;\n      /**\n       * <code>optional bytes data = 4;</code>\n       */\n      public boolean hasData() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional bytes data = 4;</code>\n       */\n      public com.google.protobuf.ByteString getData() {\n        return data_;\n      }\n      /**\n       * <code>optional bytes data = 4;</code>\n       */\n      public Builder setData(com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        data_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional bytes data = 4;</code>\n       */\n      public Builder clearData() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        data_ = getDefaultInstance().getData();\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:IMHttpWrapper)\n    }\n\n    static {\n      defaultInstance = new IMHttpWrapper(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:IMHttpWrapper)\n  }\n\n  public interface SearchUserRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string keyword = 1;\n    /**\n     * <code>required string keyword = 1;</code>\n     */\n    boolean hasKeyword();\n    /**\n     * <code>required string keyword = 1;</code>\n     */\n    java.lang.String getKeyword();\n    /**\n     * <code>required string keyword = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getKeywordBytes();\n\n    // optional int32 fuzzy = 2;\n    /**\n     * <code>optional int32 fuzzy = 2;</code>\n     */\n    boolean hasFuzzy();\n    /**\n     * <code>optional int32 fuzzy = 2;</code>\n     */\n    int getFuzzy();\n\n    // optional int32 page = 3;\n    /**\n     * <code>optional int32 page = 3;</code>\n     */\n    boolean hasPage();\n    /**\n     * <code>optional int32 page = 3;</code>\n     */\n    int getPage();\n\n    // optional string domain_id = 4;\n    /**\n     * <code>optional string domain_id = 4;</code>\n     */\n    boolean hasDomainId();\n    /**\n     * <code>optional string domain_id = 4;</code>\n     */\n    java.lang.String getDomainId();\n    /**\n     * <code>optional string domain_id = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getDomainIdBytes();\n\n    // optional int32 type = 5;\n    /**\n     * <code>optional int32 type = 5;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>optional int32 type = 5;</code>\n     */\n    int getType();\n  }\n  /**\n   * Protobuf type {@code SearchUserRequest}\n   */\n  public static final class SearchUserRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements SearchUserRequestOrBuilder {\n    // Use SearchUserRequest.newBuilder() to construct.\n    private SearchUserRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private SearchUserRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final SearchUserRequest defaultInstance;\n    public static SearchUserRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public SearchUserRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private SearchUserRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              keyword_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              fuzzy_ = input.readInt32();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              page_ = input.readInt32();\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000008;\n              domainId_ = input.readBytes();\n              break;\n            }\n            case 40: {\n              bitField0_ |= 0x00000010;\n              type_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_SearchUserRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_SearchUserRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.SearchUserRequest.class, cn.wildfirechat.proto.WFCMessage.SearchUserRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<SearchUserRequest> PARSER =\n        new com.google.protobuf.AbstractParser<SearchUserRequest>() {\n      public SearchUserRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new SearchUserRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<SearchUserRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string keyword = 1;\n    public static final int KEYWORD_FIELD_NUMBER = 1;\n    private java.lang.Object keyword_;\n    /**\n     * <code>required string keyword = 1;</code>\n     */\n    public boolean hasKeyword() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string keyword = 1;</code>\n     */\n    public java.lang.String getKeyword() {\n      java.lang.Object ref = keyword_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          keyword_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string keyword = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getKeywordBytes() {\n      java.lang.Object ref = keyword_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        keyword_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 fuzzy = 2;\n    public static final int FUZZY_FIELD_NUMBER = 2;\n    private int fuzzy_;\n    /**\n     * <code>optional int32 fuzzy = 2;</code>\n     */\n    public boolean hasFuzzy() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional int32 fuzzy = 2;</code>\n     */\n    public int getFuzzy() {\n      return fuzzy_;\n    }\n\n    // optional int32 page = 3;\n    public static final int PAGE_FIELD_NUMBER = 3;\n    private int page_;\n    /**\n     * <code>optional int32 page = 3;</code>\n     */\n    public boolean hasPage() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional int32 page = 3;</code>\n     */\n    public int getPage() {\n      return page_;\n    }\n\n    // optional string domain_id = 4;\n    public static final int DOMAIN_ID_FIELD_NUMBER = 4;\n    private java.lang.Object domainId_;\n    /**\n     * <code>optional string domain_id = 4;</code>\n     */\n    public boolean hasDomainId() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional string domain_id = 4;</code>\n     */\n    public java.lang.String getDomainId() {\n      java.lang.Object ref = domainId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          domainId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string domain_id = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDomainIdBytes() {\n      java.lang.Object ref = domainId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        domainId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 type = 5;\n    public static final int TYPE_FIELD_NUMBER = 5;\n    private int type_;\n    /**\n     * <code>optional int32 type = 5;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional int32 type = 5;</code>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    private void initFields() {\n      keyword_ = \"\";\n      fuzzy_ = 0;\n      page_ = 0;\n      domainId_ = \"\";\n      type_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasKeyword()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getKeywordBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, fuzzy_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt32(3, page_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(4, getDomainIdBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeInt32(5, type_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getKeywordBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, fuzzy_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(3, page_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, getDomainIdBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(5, type_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.SearchUserRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code SearchUserRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.SearchUserRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_SearchUserRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_SearchUserRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.SearchUserRequest.class, cn.wildfirechat.proto.WFCMessage.SearchUserRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.SearchUserRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        keyword_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        fuzzy_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        page_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        domainId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000010);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_SearchUserRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.SearchUserRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.SearchUserRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.SearchUserRequest build() {\n        cn.wildfirechat.proto.WFCMessage.SearchUserRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.SearchUserRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.SearchUserRequest result = new cn.wildfirechat.proto.WFCMessage.SearchUserRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.keyword_ = keyword_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.fuzzy_ = fuzzy_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.page_ = page_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.domainId_ = domainId_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.type_ = type_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.SearchUserRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.SearchUserRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.SearchUserRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.SearchUserRequest.getDefaultInstance()) return this;\n        if (other.hasKeyword()) {\n          bitField0_ |= 0x00000001;\n          keyword_ = other.keyword_;\n          onChanged();\n        }\n        if (other.hasFuzzy()) {\n          setFuzzy(other.getFuzzy());\n        }\n        if (other.hasPage()) {\n          setPage(other.getPage());\n        }\n        if (other.hasDomainId()) {\n          bitField0_ |= 0x00000008;\n          domainId_ = other.domainId_;\n          onChanged();\n        }\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasKeyword()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.SearchUserRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.SearchUserRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string keyword = 1;\n      private java.lang.Object keyword_ = \"\";\n      /**\n       * <code>required string keyword = 1;</code>\n       */\n      public boolean hasKeyword() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string keyword = 1;</code>\n       */\n      public java.lang.String getKeyword() {\n        java.lang.Object ref = keyword_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          keyword_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string keyword = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getKeywordBytes() {\n        java.lang.Object ref = keyword_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          keyword_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string keyword = 1;</code>\n       */\n      public Builder setKeyword(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        keyword_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string keyword = 1;</code>\n       */\n      public Builder clearKeyword() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        keyword_ = getDefaultInstance().getKeyword();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string keyword = 1;</code>\n       */\n      public Builder setKeywordBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        keyword_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 fuzzy = 2;\n      private int fuzzy_ ;\n      /**\n       * <code>optional int32 fuzzy = 2;</code>\n       */\n      public boolean hasFuzzy() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional int32 fuzzy = 2;</code>\n       */\n      public int getFuzzy() {\n        return fuzzy_;\n      }\n      /**\n       * <code>optional int32 fuzzy = 2;</code>\n       */\n      public Builder setFuzzy(int value) {\n        bitField0_ |= 0x00000002;\n        fuzzy_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 fuzzy = 2;</code>\n       */\n      public Builder clearFuzzy() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        fuzzy_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 page = 3;\n      private int page_ ;\n      /**\n       * <code>optional int32 page = 3;</code>\n       */\n      public boolean hasPage() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional int32 page = 3;</code>\n       */\n      public int getPage() {\n        return page_;\n      }\n      /**\n       * <code>optional int32 page = 3;</code>\n       */\n      public Builder setPage(int value) {\n        bitField0_ |= 0x00000004;\n        page_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 page = 3;</code>\n       */\n      public Builder clearPage() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        page_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional string domain_id = 4;\n      private java.lang.Object domainId_ = \"\";\n      /**\n       * <code>optional string domain_id = 4;</code>\n       */\n      public boolean hasDomainId() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional string domain_id = 4;</code>\n       */\n      public java.lang.String getDomainId() {\n        java.lang.Object ref = domainId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          domainId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string domain_id = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDomainIdBytes() {\n        java.lang.Object ref = domainId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          domainId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string domain_id = 4;</code>\n       */\n      public Builder setDomainId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        domainId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string domain_id = 4;</code>\n       */\n      public Builder clearDomainId() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        domainId_ = getDefaultInstance().getDomainId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string domain_id = 4;</code>\n       */\n      public Builder setDomainIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        domainId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 type = 5;\n      private int type_ ;\n      /**\n       * <code>optional int32 type = 5;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional int32 type = 5;</code>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>optional int32 type = 5;</code>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00000010;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 type = 5;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:SearchUserRequest)\n    }\n\n    static {\n      defaultInstance = new SearchUserRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:SearchUserRequest)\n  }\n\n  public interface SearchUserResultOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // repeated .User entry = 1;\n    /**\n     * <code>repeated .User entry = 1;</code>\n     */\n    java.util.List<cn.wildfirechat.proto.WFCMessage.User> \n        getEntryList();\n    /**\n     * <code>repeated .User entry = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.User getEntry(int index);\n    /**\n     * <code>repeated .User entry = 1;</code>\n     */\n    int getEntryCount();\n    /**\n     * <code>repeated .User entry = 1;</code>\n     */\n    java.util.List<? extends cn.wildfirechat.proto.WFCMessage.UserOrBuilder> \n        getEntryOrBuilderList();\n    /**\n     * <code>repeated .User entry = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.UserOrBuilder getEntryOrBuilder(\n        int index);\n  }\n  /**\n   * Protobuf type {@code SearchUserResult}\n   */\n  public static final class SearchUserResult extends\n      com.google.protobuf.GeneratedMessage\n      implements SearchUserResultOrBuilder {\n    // Use SearchUserResult.newBuilder() to construct.\n    private SearchUserResult(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private SearchUserResult(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final SearchUserResult defaultInstance;\n    public static SearchUserResult getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public SearchUserResult getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private SearchUserResult(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n                entry_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.User>();\n                mutable_bitField0_ |= 0x00000001;\n              }\n              entry_.add(input.readMessage(cn.wildfirechat.proto.WFCMessage.User.PARSER, extensionRegistry));\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) {\n          entry_ = java.util.Collections.unmodifiableList(entry_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_SearchUserResult_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_SearchUserResult_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.SearchUserResult.class, cn.wildfirechat.proto.WFCMessage.SearchUserResult.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<SearchUserResult> PARSER =\n        new com.google.protobuf.AbstractParser<SearchUserResult>() {\n      public SearchUserResult parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new SearchUserResult(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<SearchUserResult> getParserForType() {\n      return PARSER;\n    }\n\n    // repeated .User entry = 1;\n    public static final int ENTRY_FIELD_NUMBER = 1;\n    private java.util.List<cn.wildfirechat.proto.WFCMessage.User> entry_;\n    /**\n     * <code>repeated .User entry = 1;</code>\n     */\n    public java.util.List<cn.wildfirechat.proto.WFCMessage.User> getEntryList() {\n      return entry_;\n    }\n    /**\n     * <code>repeated .User entry = 1;</code>\n     */\n    public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.UserOrBuilder> \n        getEntryOrBuilderList() {\n      return entry_;\n    }\n    /**\n     * <code>repeated .User entry = 1;</code>\n     */\n    public int getEntryCount() {\n      return entry_.size();\n    }\n    /**\n     * <code>repeated .User entry = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.User getEntry(int index) {\n      return entry_.get(index);\n    }\n    /**\n     * <code>repeated .User entry = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.UserOrBuilder getEntryOrBuilder(\n        int index) {\n      return entry_.get(index);\n    }\n\n    private void initFields() {\n      entry_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      for (int i = 0; i < getEntryCount(); i++) {\n        if (!getEntry(i).isInitialized()) {\n          memoizedIsInitialized = 0;\n          return false;\n        }\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      for (int i = 0; i < entry_.size(); i++) {\n        output.writeMessage(1, entry_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      for (int i = 0; i < entry_.size(); i++) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, entry_.get(i));\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserResult parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserResult parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserResult parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserResult parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserResult parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserResult parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserResult parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserResult parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserResult parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.SearchUserResult parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.SearchUserResult prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code SearchUserResult}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.SearchUserResultOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_SearchUserResult_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_SearchUserResult_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.SearchUserResult.class, cn.wildfirechat.proto.WFCMessage.SearchUserResult.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.SearchUserResult.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getEntryFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (entryBuilder_ == null) {\n          entry_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n        } else {\n          entryBuilder_.clear();\n        }\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_SearchUserResult_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.SearchUserResult getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.SearchUserResult.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.SearchUserResult build() {\n        cn.wildfirechat.proto.WFCMessage.SearchUserResult result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.SearchUserResult buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.SearchUserResult result = new cn.wildfirechat.proto.WFCMessage.SearchUserResult(this);\n        int from_bitField0_ = bitField0_;\n        if (entryBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001)) {\n            entry_ = java.util.Collections.unmodifiableList(entry_);\n            bitField0_ = (bitField0_ & ~0x00000001);\n          }\n          result.entry_ = entry_;\n        } else {\n          result.entry_ = entryBuilder_.build();\n        }\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.SearchUserResult) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.SearchUserResult)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.SearchUserResult other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.SearchUserResult.getDefaultInstance()) return this;\n        if (entryBuilder_ == null) {\n          if (!other.entry_.isEmpty()) {\n            if (entry_.isEmpty()) {\n              entry_ = other.entry_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n            } else {\n              ensureEntryIsMutable();\n              entry_.addAll(other.entry_);\n            }\n            onChanged();\n          }\n        } else {\n          if (!other.entry_.isEmpty()) {\n            if (entryBuilder_.isEmpty()) {\n              entryBuilder_.dispose();\n              entryBuilder_ = null;\n              entry_ = other.entry_;\n              bitField0_ = (bitField0_ & ~0x00000001);\n              entryBuilder_ = \n                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n                   getEntryFieldBuilder() : null;\n            } else {\n              entryBuilder_.addAllMessages(other.entry_);\n            }\n          }\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        for (int i = 0; i < getEntryCount(); i++) {\n          if (!getEntry(i).isInitialized()) {\n            \n            return false;\n          }\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.SearchUserResult parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.SearchUserResult) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // repeated .User entry = 1;\n      private java.util.List<cn.wildfirechat.proto.WFCMessage.User> entry_ =\n        java.util.Collections.emptyList();\n      private void ensureEntryIsMutable() {\n        if (!((bitField0_ & 0x00000001) == 0x00000001)) {\n          entry_ = new java.util.ArrayList<cn.wildfirechat.proto.WFCMessage.User>(entry_);\n          bitField0_ |= 0x00000001;\n         }\n      }\n\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.User, cn.wildfirechat.proto.WFCMessage.User.Builder, cn.wildfirechat.proto.WFCMessage.UserOrBuilder> entryBuilder_;\n\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.User> getEntryList() {\n        if (entryBuilder_ == null) {\n          return java.util.Collections.unmodifiableList(entry_);\n        } else {\n          return entryBuilder_.getMessageList();\n        }\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public int getEntryCount() {\n        if (entryBuilder_ == null) {\n          return entry_.size();\n        } else {\n          return entryBuilder_.getCount();\n        }\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.User getEntry(int index) {\n        if (entryBuilder_ == null) {\n          return entry_.get(index);\n        } else {\n          return entryBuilder_.getMessage(index);\n        }\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public Builder setEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.User value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.set(index, value);\n          onChanged();\n        } else {\n          entryBuilder_.setMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public Builder setEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.User.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.set(index, builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.setMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public Builder addEntry(cn.wildfirechat.proto.WFCMessage.User value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.add(value);\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public Builder addEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.User value) {\n        if (entryBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          ensureEntryIsMutable();\n          entry_.add(index, value);\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(index, value);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public Builder addEntry(\n          cn.wildfirechat.proto.WFCMessage.User.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.add(builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public Builder addEntry(\n          int index, cn.wildfirechat.proto.WFCMessage.User.Builder builderForValue) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.add(index, builderForValue.build());\n          onChanged();\n        } else {\n          entryBuilder_.addMessage(index, builderForValue.build());\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public Builder addAllEntry(\n          java.lang.Iterable<? extends cn.wildfirechat.proto.WFCMessage.User> values) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          super.addAll(values, entry_);\n          onChanged();\n        } else {\n          entryBuilder_.addAllMessages(values);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public Builder clearEntry() {\n        if (entryBuilder_ == null) {\n          entry_ = java.util.Collections.emptyList();\n          bitField0_ = (bitField0_ & ~0x00000001);\n          onChanged();\n        } else {\n          entryBuilder_.clear();\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public Builder removeEntry(int index) {\n        if (entryBuilder_ == null) {\n          ensureEntryIsMutable();\n          entry_.remove(index);\n          onChanged();\n        } else {\n          entryBuilder_.remove(index);\n        }\n        return this;\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.User.Builder getEntryBuilder(\n          int index) {\n        return getEntryFieldBuilder().getBuilder(index);\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.UserOrBuilder getEntryOrBuilder(\n          int index) {\n        if (entryBuilder_ == null) {\n          return entry_.get(index);  } else {\n          return entryBuilder_.getMessageOrBuilder(index);\n        }\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public java.util.List<? extends cn.wildfirechat.proto.WFCMessage.UserOrBuilder> \n           getEntryOrBuilderList() {\n        if (entryBuilder_ != null) {\n          return entryBuilder_.getMessageOrBuilderList();\n        } else {\n          return java.util.Collections.unmodifiableList(entry_);\n        }\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.User.Builder addEntryBuilder() {\n        return getEntryFieldBuilder().addBuilder(\n            cn.wildfirechat.proto.WFCMessage.User.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.User.Builder addEntryBuilder(\n          int index) {\n        return getEntryFieldBuilder().addBuilder(\n            index, cn.wildfirechat.proto.WFCMessage.User.getDefaultInstance());\n      }\n      /**\n       * <code>repeated .User entry = 1;</code>\n       */\n      public java.util.List<cn.wildfirechat.proto.WFCMessage.User.Builder> \n           getEntryBuilderList() {\n        return getEntryFieldBuilder().getBuilderList();\n      }\n      private com.google.protobuf.RepeatedFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.User, cn.wildfirechat.proto.WFCMessage.User.Builder, cn.wildfirechat.proto.WFCMessage.UserOrBuilder> \n          getEntryFieldBuilder() {\n        if (entryBuilder_ == null) {\n          entryBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.User, cn.wildfirechat.proto.WFCMessage.User.Builder, cn.wildfirechat.proto.WFCMessage.UserOrBuilder>(\n                  entry_,\n                  ((bitField0_ & 0x00000001) == 0x00000001),\n                  getParentForChildren(),\n                  isClean());\n          entry_ = null;\n        }\n        return entryBuilder_;\n      }\n\n      // @@protoc_insertion_point(builder_scope:SearchUserResult)\n    }\n\n    static {\n      defaultInstance = new SearchUserResult(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:SearchUserResult)\n  }\n\n  public interface GetChatroomInfoRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string chatroom_id = 1;\n    /**\n     * <code>required string chatroom_id = 1;</code>\n     */\n    boolean hasChatroomId();\n    /**\n     * <code>required string chatroom_id = 1;</code>\n     */\n    java.lang.String getChatroomId();\n    /**\n     * <code>required string chatroom_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getChatroomIdBytes();\n\n    // optional int64 update_dt = 2;\n    /**\n     * <code>optional int64 update_dt = 2;</code>\n     */\n    boolean hasUpdateDt();\n    /**\n     * <code>optional int64 update_dt = 2;</code>\n     */\n    long getUpdateDt();\n  }\n  /**\n   * Protobuf type {@code GetChatroomInfoRequest}\n   */\n  public static final class GetChatroomInfoRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements GetChatroomInfoRequestOrBuilder {\n    // Use GetChatroomInfoRequest.newBuilder() to construct.\n    private GetChatroomInfoRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private GetChatroomInfoRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final GetChatroomInfoRequest defaultInstance;\n    public static GetChatroomInfoRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public GetChatroomInfoRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private GetChatroomInfoRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              chatroomId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              updateDt_ = input.readInt64();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetChatroomInfoRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetChatroomInfoRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest.class, cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<GetChatroomInfoRequest> PARSER =\n        new com.google.protobuf.AbstractParser<GetChatroomInfoRequest>() {\n      public GetChatroomInfoRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new GetChatroomInfoRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<GetChatroomInfoRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string chatroom_id = 1;\n    public static final int CHATROOM_ID_FIELD_NUMBER = 1;\n    private java.lang.Object chatroomId_;\n    /**\n     * <code>required string chatroom_id = 1;</code>\n     */\n    public boolean hasChatroomId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string chatroom_id = 1;</code>\n     */\n    public java.lang.String getChatroomId() {\n      java.lang.Object ref = chatroomId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          chatroomId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string chatroom_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getChatroomIdBytes() {\n      java.lang.Object ref = chatroomId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        chatroomId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int64 update_dt = 2;\n    public static final int UPDATE_DT_FIELD_NUMBER = 2;\n    private long updateDt_;\n    /**\n     * <code>optional int64 update_dt = 2;</code>\n     */\n    public boolean hasUpdateDt() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional int64 update_dt = 2;</code>\n     */\n    public long getUpdateDt() {\n      return updateDt_;\n    }\n\n    private void initFields() {\n      chatroomId_ = \"\";\n      updateDt_ = 0L;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasChatroomId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getChatroomIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt64(2, updateDt_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getChatroomIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(2, updateDt_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code GetChatroomInfoRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetChatroomInfoRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetChatroomInfoRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest.class, cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        chatroomId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        updateDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetChatroomInfoRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest build() {\n        cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest result = new cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.chatroomId_ = chatroomId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.updateDt_ = updateDt_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest.getDefaultInstance()) return this;\n        if (other.hasChatroomId()) {\n          bitField0_ |= 0x00000001;\n          chatroomId_ = other.chatroomId_;\n          onChanged();\n        }\n        if (other.hasUpdateDt()) {\n          setUpdateDt(other.getUpdateDt());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasChatroomId()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.GetChatroomInfoRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string chatroom_id = 1;\n      private java.lang.Object chatroomId_ = \"\";\n      /**\n       * <code>required string chatroom_id = 1;</code>\n       */\n      public boolean hasChatroomId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string chatroom_id = 1;</code>\n       */\n      public java.lang.String getChatroomId() {\n        java.lang.Object ref = chatroomId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          chatroomId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string chatroom_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getChatroomIdBytes() {\n        java.lang.Object ref = chatroomId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          chatroomId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string chatroom_id = 1;</code>\n       */\n      public Builder setChatroomId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        chatroomId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string chatroom_id = 1;</code>\n       */\n      public Builder clearChatroomId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        chatroomId_ = getDefaultInstance().getChatroomId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string chatroom_id = 1;</code>\n       */\n      public Builder setChatroomIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        chatroomId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 update_dt = 2;\n      private long updateDt_ ;\n      /**\n       * <code>optional int64 update_dt = 2;</code>\n       */\n      public boolean hasUpdateDt() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional int64 update_dt = 2;</code>\n       */\n      public long getUpdateDt() {\n        return updateDt_;\n      }\n      /**\n       * <code>optional int64 update_dt = 2;</code>\n       */\n      public Builder setUpdateDt(long value) {\n        bitField0_ |= 0x00000002;\n        updateDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 update_dt = 2;</code>\n       */\n      public Builder clearUpdateDt() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        updateDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:GetChatroomInfoRequest)\n    }\n\n    static {\n      defaultInstance = new GetChatroomInfoRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:GetChatroomInfoRequest)\n  }\n\n  public interface ChatroomInfoOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string title = 1;\n    /**\n     * <code>required string title = 1;</code>\n     */\n    boolean hasTitle();\n    /**\n     * <code>required string title = 1;</code>\n     */\n    java.lang.String getTitle();\n    /**\n     * <code>required string title = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getTitleBytes();\n\n    // optional string desc = 2;\n    /**\n     * <code>optional string desc = 2;</code>\n     */\n    boolean hasDesc();\n    /**\n     * <code>optional string desc = 2;</code>\n     */\n    java.lang.String getDesc();\n    /**\n     * <code>optional string desc = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getDescBytes();\n\n    // optional string portrait = 3;\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    boolean hasPortrait();\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    java.lang.String getPortrait();\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getPortraitBytes();\n\n    // optional int32 member_count = 4;\n    /**\n     * <code>optional int32 member_count = 4;</code>\n     */\n    boolean hasMemberCount();\n    /**\n     * <code>optional int32 member_count = 4;</code>\n     */\n    int getMemberCount();\n\n    // optional int64 create_dt = 5;\n    /**\n     * <code>optional int64 create_dt = 5;</code>\n     */\n    boolean hasCreateDt();\n    /**\n     * <code>optional int64 create_dt = 5;</code>\n     */\n    long getCreateDt();\n\n    // optional int64 update_dt = 6;\n    /**\n     * <code>optional int64 update_dt = 6;</code>\n     */\n    boolean hasUpdateDt();\n    /**\n     * <code>optional int64 update_dt = 6;</code>\n     */\n    long getUpdateDt();\n\n    // optional string extra = 7;\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    boolean hasExtra();\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    java.lang.String getExtra();\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    com.google.protobuf.ByteString\n        getExtraBytes();\n\n    // optional int32 state = 8;\n    /**\n     * <code>optional int32 state = 8;</code>\n     */\n    boolean hasState();\n    /**\n     * <code>optional int32 state = 8;</code>\n     */\n    int getState();\n  }\n  /**\n   * Protobuf type {@code ChatroomInfo}\n   */\n  public static final class ChatroomInfo extends\n      com.google.protobuf.GeneratedMessage\n      implements ChatroomInfoOrBuilder {\n    // Use ChatroomInfo.newBuilder() to construct.\n    private ChatroomInfo(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ChatroomInfo(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ChatroomInfo defaultInstance;\n    public static ChatroomInfo getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ChatroomInfo getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ChatroomInfo(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              title_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              desc_ = input.readBytes();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              portrait_ = input.readBytes();\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000008;\n              memberCount_ = input.readInt32();\n              break;\n            }\n            case 40: {\n              bitField0_ |= 0x00000010;\n              createDt_ = input.readInt64();\n              break;\n            }\n            case 48: {\n              bitField0_ |= 0x00000020;\n              updateDt_ = input.readInt64();\n              break;\n            }\n            case 58: {\n              bitField0_ |= 0x00000040;\n              extra_ = input.readBytes();\n              break;\n            }\n            case 64: {\n              bitField0_ |= 0x00000080;\n              state_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ChatroomInfo_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ChatroomInfo_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ChatroomInfo.class, cn.wildfirechat.proto.WFCMessage.ChatroomInfo.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ChatroomInfo> PARSER =\n        new com.google.protobuf.AbstractParser<ChatroomInfo>() {\n      public ChatroomInfo parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ChatroomInfo(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ChatroomInfo> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string title = 1;\n    public static final int TITLE_FIELD_NUMBER = 1;\n    private java.lang.Object title_;\n    /**\n     * <code>required string title = 1;</code>\n     */\n    public boolean hasTitle() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string title = 1;</code>\n     */\n    public java.lang.String getTitle() {\n      java.lang.Object ref = title_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          title_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string title = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTitleBytes() {\n      java.lang.Object ref = title_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        title_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string desc = 2;\n    public static final int DESC_FIELD_NUMBER = 2;\n    private java.lang.Object desc_;\n    /**\n     * <code>optional string desc = 2;</code>\n     */\n    public boolean hasDesc() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional string desc = 2;</code>\n     */\n    public java.lang.String getDesc() {\n      java.lang.Object ref = desc_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          desc_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string desc = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDescBytes() {\n      java.lang.Object ref = desc_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        desc_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string portrait = 3;\n    public static final int PORTRAIT_FIELD_NUMBER = 3;\n    private java.lang.Object portrait_;\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    public boolean hasPortrait() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    public java.lang.String getPortrait() {\n      java.lang.Object ref = portrait_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          portrait_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string portrait = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getPortraitBytes() {\n      java.lang.Object ref = portrait_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        portrait_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 member_count = 4;\n    public static final int MEMBER_COUNT_FIELD_NUMBER = 4;\n    private int memberCount_;\n    /**\n     * <code>optional int32 member_count = 4;</code>\n     */\n    public boolean hasMemberCount() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional int32 member_count = 4;</code>\n     */\n    public int getMemberCount() {\n      return memberCount_;\n    }\n\n    // optional int64 create_dt = 5;\n    public static final int CREATE_DT_FIELD_NUMBER = 5;\n    private long createDt_;\n    /**\n     * <code>optional int64 create_dt = 5;</code>\n     */\n    public boolean hasCreateDt() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional int64 create_dt = 5;</code>\n     */\n    public long getCreateDt() {\n      return createDt_;\n    }\n\n    // optional int64 update_dt = 6;\n    public static final int UPDATE_DT_FIELD_NUMBER = 6;\n    private long updateDt_;\n    /**\n     * <code>optional int64 update_dt = 6;</code>\n     */\n    public boolean hasUpdateDt() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional int64 update_dt = 6;</code>\n     */\n    public long getUpdateDt() {\n      return updateDt_;\n    }\n\n    // optional string extra = 7;\n    public static final int EXTRA_FIELD_NUMBER = 7;\n    private java.lang.Object extra_;\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    public boolean hasExtra() {\n      return ((bitField0_ & 0x00000040) == 0x00000040);\n    }\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    public java.lang.String getExtra() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          extra_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string extra = 7;</code>\n     */\n    public com.google.protobuf.ByteString\n        getExtraBytes() {\n      java.lang.Object ref = extra_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        extra_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 state = 8;\n    public static final int STATE_FIELD_NUMBER = 8;\n    private int state_;\n    /**\n     * <code>optional int32 state = 8;</code>\n     */\n    public boolean hasState() {\n      return ((bitField0_ & 0x00000080) == 0x00000080);\n    }\n    /**\n     * <code>optional int32 state = 8;</code>\n     */\n    public int getState() {\n      return state_;\n    }\n\n    private void initFields() {\n      title_ = \"\";\n      desc_ = \"\";\n      portrait_ = \"\";\n      memberCount_ = 0;\n      createDt_ = 0L;\n      updateDt_ = 0L;\n      extra_ = \"\";\n      state_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasTitle()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getTitleBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getDescBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getPortraitBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeInt32(4, memberCount_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeInt64(5, createDt_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeInt64(6, updateDt_);\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        output.writeBytes(7, getExtraBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        output.writeInt32(8, state_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getTitleBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getDescBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getPortraitBytes());\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(4, memberCount_);\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(5, createDt_);\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(6, updateDt_);\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(7, getExtraBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(8, state_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomInfo parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomInfo parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomInfo parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomInfo parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomInfo parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomInfo parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomInfo parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomInfo parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomInfo parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomInfo parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ChatroomInfo prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ChatroomInfo}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ChatroomInfoOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChatroomInfo_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChatroomInfo_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ChatroomInfo.class, cn.wildfirechat.proto.WFCMessage.ChatroomInfo.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ChatroomInfo.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        title_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        desc_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        portrait_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        memberCount_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        createDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000010);\n        updateDt_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000020);\n        extra_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000040);\n        state_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000080);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChatroomInfo_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChatroomInfo getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ChatroomInfo.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChatroomInfo build() {\n        cn.wildfirechat.proto.WFCMessage.ChatroomInfo result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChatroomInfo buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ChatroomInfo result = new cn.wildfirechat.proto.WFCMessage.ChatroomInfo(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.title_ = title_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.desc_ = desc_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.portrait_ = portrait_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.memberCount_ = memberCount_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.createDt_ = createDt_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.updateDt_ = updateDt_;\n        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {\n          to_bitField0_ |= 0x00000040;\n        }\n        result.extra_ = extra_;\n        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {\n          to_bitField0_ |= 0x00000080;\n        }\n        result.state_ = state_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ChatroomInfo) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ChatroomInfo)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ChatroomInfo other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ChatroomInfo.getDefaultInstance()) return this;\n        if (other.hasTitle()) {\n          bitField0_ |= 0x00000001;\n          title_ = other.title_;\n          onChanged();\n        }\n        if (other.hasDesc()) {\n          bitField0_ |= 0x00000002;\n          desc_ = other.desc_;\n          onChanged();\n        }\n        if (other.hasPortrait()) {\n          bitField0_ |= 0x00000004;\n          portrait_ = other.portrait_;\n          onChanged();\n        }\n        if (other.hasMemberCount()) {\n          setMemberCount(other.getMemberCount());\n        }\n        if (other.hasCreateDt()) {\n          setCreateDt(other.getCreateDt());\n        }\n        if (other.hasUpdateDt()) {\n          setUpdateDt(other.getUpdateDt());\n        }\n        if (other.hasExtra()) {\n          bitField0_ |= 0x00000040;\n          extra_ = other.extra_;\n          onChanged();\n        }\n        if (other.hasState()) {\n          setState(other.getState());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasTitle()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ChatroomInfo parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ChatroomInfo) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string title = 1;\n      private java.lang.Object title_ = \"\";\n      /**\n       * <code>required string title = 1;</code>\n       */\n      public boolean hasTitle() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string title = 1;</code>\n       */\n      public java.lang.String getTitle() {\n        java.lang.Object ref = title_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          title_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string title = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTitleBytes() {\n        java.lang.Object ref = title_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          title_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string title = 1;</code>\n       */\n      public Builder setTitle(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        title_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string title = 1;</code>\n       */\n      public Builder clearTitle() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        title_ = getDefaultInstance().getTitle();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string title = 1;</code>\n       */\n      public Builder setTitleBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        title_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string desc = 2;\n      private java.lang.Object desc_ = \"\";\n      /**\n       * <code>optional string desc = 2;</code>\n       */\n      public boolean hasDesc() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional string desc = 2;</code>\n       */\n      public java.lang.String getDesc() {\n        java.lang.Object ref = desc_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          desc_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string desc = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDescBytes() {\n        java.lang.Object ref = desc_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          desc_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string desc = 2;</code>\n       */\n      public Builder setDesc(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        desc_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string desc = 2;</code>\n       */\n      public Builder clearDesc() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        desc_ = getDefaultInstance().getDesc();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string desc = 2;</code>\n       */\n      public Builder setDescBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        desc_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string portrait = 3;\n      private java.lang.Object portrait_ = \"\";\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public boolean hasPortrait() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public java.lang.String getPortrait() {\n        java.lang.Object ref = portrait_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          portrait_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getPortraitBytes() {\n        java.lang.Object ref = portrait_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          portrait_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public Builder setPortrait(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        portrait_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public Builder clearPortrait() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        portrait_ = getDefaultInstance().getPortrait();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string portrait = 3;</code>\n       */\n      public Builder setPortraitBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        portrait_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 member_count = 4;\n      private int memberCount_ ;\n      /**\n       * <code>optional int32 member_count = 4;</code>\n       */\n      public boolean hasMemberCount() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional int32 member_count = 4;</code>\n       */\n      public int getMemberCount() {\n        return memberCount_;\n      }\n      /**\n       * <code>optional int32 member_count = 4;</code>\n       */\n      public Builder setMemberCount(int value) {\n        bitField0_ |= 0x00000008;\n        memberCount_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 member_count = 4;</code>\n       */\n      public Builder clearMemberCount() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        memberCount_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 create_dt = 5;\n      private long createDt_ ;\n      /**\n       * <code>optional int64 create_dt = 5;</code>\n       */\n      public boolean hasCreateDt() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional int64 create_dt = 5;</code>\n       */\n      public long getCreateDt() {\n        return createDt_;\n      }\n      /**\n       * <code>optional int64 create_dt = 5;</code>\n       */\n      public Builder setCreateDt(long value) {\n        bitField0_ |= 0x00000010;\n        createDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 create_dt = 5;</code>\n       */\n      public Builder clearCreateDt() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        createDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional int64 update_dt = 6;\n      private long updateDt_ ;\n      /**\n       * <code>optional int64 update_dt = 6;</code>\n       */\n      public boolean hasUpdateDt() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional int64 update_dt = 6;</code>\n       */\n      public long getUpdateDt() {\n        return updateDt_;\n      }\n      /**\n       * <code>optional int64 update_dt = 6;</code>\n       */\n      public Builder setUpdateDt(long value) {\n        bitField0_ |= 0x00000020;\n        updateDt_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int64 update_dt = 6;</code>\n       */\n      public Builder clearUpdateDt() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        updateDt_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // optional string extra = 7;\n      private java.lang.Object extra_ = \"\";\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public boolean hasExtra() {\n        return ((bitField0_ & 0x00000040) == 0x00000040);\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public java.lang.String getExtra() {\n        java.lang.Object ref = extra_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          extra_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public com.google.protobuf.ByteString\n          getExtraBytes() {\n        java.lang.Object ref = extra_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          extra_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public Builder setExtra(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public Builder clearExtra() {\n        bitField0_ = (bitField0_ & ~0x00000040);\n        extra_ = getDefaultInstance().getExtra();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string extra = 7;</code>\n       */\n      public Builder setExtraBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        extra_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 state = 8;\n      private int state_ ;\n      /**\n       * <code>optional int32 state = 8;</code>\n       */\n      public boolean hasState() {\n        return ((bitField0_ & 0x00000080) == 0x00000080);\n      }\n      /**\n       * <code>optional int32 state = 8;</code>\n       */\n      public int getState() {\n        return state_;\n      }\n      /**\n       * <code>optional int32 state = 8;</code>\n       */\n      public Builder setState(int value) {\n        bitField0_ |= 0x00000080;\n        state_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 state = 8;</code>\n       */\n      public Builder clearState() {\n        bitField0_ = (bitField0_ & ~0x00000080);\n        state_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ChatroomInfo)\n    }\n\n    static {\n      defaultInstance = new ChatroomInfo(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ChatroomInfo)\n  }\n\n  public interface GetChatroomMemberInfoRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string chatroom_id = 1;\n    /**\n     * <code>required string chatroom_id = 1;</code>\n     */\n    boolean hasChatroomId();\n    /**\n     * <code>required string chatroom_id = 1;</code>\n     */\n    java.lang.String getChatroomId();\n    /**\n     * <code>required string chatroom_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getChatroomIdBytes();\n\n    // optional int32 max_count = 2;\n    /**\n     * <code>optional int32 max_count = 2;</code>\n     */\n    boolean hasMaxCount();\n    /**\n     * <code>optional int32 max_count = 2;</code>\n     */\n    int getMaxCount();\n  }\n  /**\n   * Protobuf type {@code GetChatroomMemberInfoRequest}\n   */\n  public static final class GetChatroomMemberInfoRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements GetChatroomMemberInfoRequestOrBuilder {\n    // Use GetChatroomMemberInfoRequest.newBuilder() to construct.\n    private GetChatroomMemberInfoRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private GetChatroomMemberInfoRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final GetChatroomMemberInfoRequest defaultInstance;\n    public static GetChatroomMemberInfoRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public GetChatroomMemberInfoRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private GetChatroomMemberInfoRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              chatroomId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              maxCount_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetChatroomMemberInfoRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetChatroomMemberInfoRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest.class, cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<GetChatroomMemberInfoRequest> PARSER =\n        new com.google.protobuf.AbstractParser<GetChatroomMemberInfoRequest>() {\n      public GetChatroomMemberInfoRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new GetChatroomMemberInfoRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<GetChatroomMemberInfoRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string chatroom_id = 1;\n    public static final int CHATROOM_ID_FIELD_NUMBER = 1;\n    private java.lang.Object chatroomId_;\n    /**\n     * <code>required string chatroom_id = 1;</code>\n     */\n    public boolean hasChatroomId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string chatroom_id = 1;</code>\n     */\n    public java.lang.String getChatroomId() {\n      java.lang.Object ref = chatroomId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          chatroomId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string chatroom_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getChatroomIdBytes() {\n      java.lang.Object ref = chatroomId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        chatroomId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 max_count = 2;\n    public static final int MAX_COUNT_FIELD_NUMBER = 2;\n    private int maxCount_;\n    /**\n     * <code>optional int32 max_count = 2;</code>\n     */\n    public boolean hasMaxCount() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional int32 max_count = 2;</code>\n     */\n    public int getMaxCount() {\n      return maxCount_;\n    }\n\n    private void initFields() {\n      chatroomId_ = \"\";\n      maxCount_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasChatroomId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getChatroomIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, maxCount_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getChatroomIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, maxCount_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code GetChatroomMemberInfoRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetChatroomMemberInfoRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetChatroomMemberInfoRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest.class, cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        chatroomId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        maxCount_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetChatroomMemberInfoRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest build() {\n        cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest result = new cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.chatroomId_ = chatroomId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.maxCount_ = maxCount_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest.getDefaultInstance()) return this;\n        if (other.hasChatroomId()) {\n          bitField0_ |= 0x00000001;\n          chatroomId_ = other.chatroomId_;\n          onChanged();\n        }\n        if (other.hasMaxCount()) {\n          setMaxCount(other.getMaxCount());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasChatroomId()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.GetChatroomMemberInfoRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string chatroom_id = 1;\n      private java.lang.Object chatroomId_ = \"\";\n      /**\n       * <code>required string chatroom_id = 1;</code>\n       */\n      public boolean hasChatroomId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string chatroom_id = 1;</code>\n       */\n      public java.lang.String getChatroomId() {\n        java.lang.Object ref = chatroomId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          chatroomId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string chatroom_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getChatroomIdBytes() {\n        java.lang.Object ref = chatroomId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          chatroomId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string chatroom_id = 1;</code>\n       */\n      public Builder setChatroomId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        chatroomId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string chatroom_id = 1;</code>\n       */\n      public Builder clearChatroomId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        chatroomId_ = getDefaultInstance().getChatroomId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string chatroom_id = 1;</code>\n       */\n      public Builder setChatroomIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        chatroomId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 max_count = 2;\n      private int maxCount_ ;\n      /**\n       * <code>optional int32 max_count = 2;</code>\n       */\n      public boolean hasMaxCount() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional int32 max_count = 2;</code>\n       */\n      public int getMaxCount() {\n        return maxCount_;\n      }\n      /**\n       * <code>optional int32 max_count = 2;</code>\n       */\n      public Builder setMaxCount(int value) {\n        bitField0_ |= 0x00000002;\n        maxCount_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 max_count = 2;</code>\n       */\n      public Builder clearMaxCount() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        maxCount_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:GetChatroomMemberInfoRequest)\n    }\n\n    static {\n      defaultInstance = new GetChatroomMemberInfoRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:GetChatroomMemberInfoRequest)\n  }\n\n  public interface ChatroomMemberInfoOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // optional int32 member_count = 1;\n    /**\n     * <code>optional int32 member_count = 1;</code>\n     */\n    boolean hasMemberCount();\n    /**\n     * <code>optional int32 member_count = 1;</code>\n     */\n    int getMemberCount();\n\n    // repeated string members = 2;\n    /**\n     * <code>repeated string members = 2;</code>\n     */\n    java.util.List<java.lang.String>\n    getMembersList();\n    /**\n     * <code>repeated string members = 2;</code>\n     */\n    int getMembersCount();\n    /**\n     * <code>repeated string members = 2;</code>\n     */\n    java.lang.String getMembers(int index);\n    /**\n     * <code>repeated string members = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getMembersBytes(int index);\n  }\n  /**\n   * Protobuf type {@code ChatroomMemberInfo}\n   */\n  public static final class ChatroomMemberInfo extends\n      com.google.protobuf.GeneratedMessage\n      implements ChatroomMemberInfoOrBuilder {\n    // Use ChatroomMemberInfo.newBuilder() to construct.\n    private ChatroomMemberInfo(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ChatroomMemberInfo(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ChatroomMemberInfo defaultInstance;\n    public static ChatroomMemberInfo getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ChatroomMemberInfo getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ChatroomMemberInfo(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              memberCount_ = input.readInt32();\n              break;\n            }\n            case 18: {\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n                members_ = new com.google.protobuf.LazyStringArrayList();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              members_.add(input.readBytes());\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n          members_ = new com.google.protobuf.UnmodifiableLazyStringList(members_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ChatroomMemberInfo_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ChatroomMemberInfo_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo.class, cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ChatroomMemberInfo> PARSER =\n        new com.google.protobuf.AbstractParser<ChatroomMemberInfo>() {\n      public ChatroomMemberInfo parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ChatroomMemberInfo(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ChatroomMemberInfo> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // optional int32 member_count = 1;\n    public static final int MEMBER_COUNT_FIELD_NUMBER = 1;\n    private int memberCount_;\n    /**\n     * <code>optional int32 member_count = 1;</code>\n     */\n    public boolean hasMemberCount() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional int32 member_count = 1;</code>\n     */\n    public int getMemberCount() {\n      return memberCount_;\n    }\n\n    // repeated string members = 2;\n    public static final int MEMBERS_FIELD_NUMBER = 2;\n    private com.google.protobuf.LazyStringList members_;\n    /**\n     * <code>repeated string members = 2;</code>\n     */\n    public java.util.List<java.lang.String>\n        getMembersList() {\n      return members_;\n    }\n    /**\n     * <code>repeated string members = 2;</code>\n     */\n    public int getMembersCount() {\n      return members_.size();\n    }\n    /**\n     * <code>repeated string members = 2;</code>\n     */\n    public java.lang.String getMembers(int index) {\n      return members_.get(index);\n    }\n    /**\n     * <code>repeated string members = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getMembersBytes(int index) {\n      return members_.getByteString(index);\n    }\n\n    private void initFields() {\n      memberCount_ = 0;\n      members_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt32(1, memberCount_);\n      }\n      for (int i = 0; i < members_.size(); i++) {\n        output.writeBytes(2, members_.getByteString(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(1, memberCount_);\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < members_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeBytesSizeNoTag(members_.getByteString(i));\n        }\n        size += dataSize;\n        size += 1 * getMembersList().size();\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ChatroomMemberInfo}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfoOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChatroomMemberInfo_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChatroomMemberInfo_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo.class, cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        memberCount_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        members_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ChatroomMemberInfo_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo build() {\n        cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo result = new cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.memberCount_ = memberCount_;\n        if (((bitField0_ & 0x00000002) == 0x00000002)) {\n          members_ = new com.google.protobuf.UnmodifiableLazyStringList(\n              members_);\n          bitField0_ = (bitField0_ & ~0x00000002);\n        }\n        result.members_ = members_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo.getDefaultInstance()) return this;\n        if (other.hasMemberCount()) {\n          setMemberCount(other.getMemberCount());\n        }\n        if (!other.members_.isEmpty()) {\n          if (members_.isEmpty()) {\n            members_ = other.members_;\n            bitField0_ = (bitField0_ & ~0x00000002);\n          } else {\n            ensureMembersIsMutable();\n            members_.addAll(other.members_);\n          }\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ChatroomMemberInfo) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // optional int32 member_count = 1;\n      private int memberCount_ ;\n      /**\n       * <code>optional int32 member_count = 1;</code>\n       */\n      public boolean hasMemberCount() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional int32 member_count = 1;</code>\n       */\n      public int getMemberCount() {\n        return memberCount_;\n      }\n      /**\n       * <code>optional int32 member_count = 1;</code>\n       */\n      public Builder setMemberCount(int value) {\n        bitField0_ |= 0x00000001;\n        memberCount_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 member_count = 1;</code>\n       */\n      public Builder clearMemberCount() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        memberCount_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // repeated string members = 2;\n      private com.google.protobuf.LazyStringList members_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      private void ensureMembersIsMutable() {\n        if (!((bitField0_ & 0x00000002) == 0x00000002)) {\n          members_ = new com.google.protobuf.LazyStringArrayList(members_);\n          bitField0_ |= 0x00000002;\n         }\n      }\n      /**\n       * <code>repeated string members = 2;</code>\n       */\n      public java.util.List<java.lang.String>\n          getMembersList() {\n        return java.util.Collections.unmodifiableList(members_);\n      }\n      /**\n       * <code>repeated string members = 2;</code>\n       */\n      public int getMembersCount() {\n        return members_.size();\n      }\n      /**\n       * <code>repeated string members = 2;</code>\n       */\n      public java.lang.String getMembers(int index) {\n        return members_.get(index);\n      }\n      /**\n       * <code>repeated string members = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getMembersBytes(int index) {\n        return members_.getByteString(index);\n      }\n      /**\n       * <code>repeated string members = 2;</code>\n       */\n      public Builder setMembers(\n          int index, java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureMembersIsMutable();\n        members_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string members = 2;</code>\n       */\n      public Builder addMembers(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureMembersIsMutable();\n        members_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string members = 2;</code>\n       */\n      public Builder addAllMembers(\n          java.lang.Iterable<java.lang.String> values) {\n        ensureMembersIsMutable();\n        super.addAll(values, members_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string members = 2;</code>\n       */\n      public Builder clearMembers() {\n        members_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string members = 2;</code>\n       */\n      public Builder addMembersBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureMembersIsMutable();\n        members_.add(value);\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ChatroomMemberInfo)\n    }\n\n    static {\n      defaultInstance = new ChatroomMemberInfo(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ChatroomMemberInfo)\n  }\n\n  public interface INT64BufOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int64 id = 1;\n    /**\n     * <code>required int64 id = 1;</code>\n     */\n    boolean hasId();\n    /**\n     * <code>required int64 id = 1;</code>\n     */\n    long getId();\n  }\n  /**\n   * Protobuf type {@code INT64Buf}\n   */\n  public static final class INT64Buf extends\n      com.google.protobuf.GeneratedMessage\n      implements INT64BufOrBuilder {\n    // Use INT64Buf.newBuilder() to construct.\n    private INT64Buf(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private INT64Buf(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final INT64Buf defaultInstance;\n    public static INT64Buf getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public INT64Buf getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private INT64Buf(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              id_ = input.readInt64();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_INT64Buf_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_INT64Buf_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.INT64Buf.class, cn.wildfirechat.proto.WFCMessage.INT64Buf.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<INT64Buf> PARSER =\n        new com.google.protobuf.AbstractParser<INT64Buf>() {\n      public INT64Buf parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new INT64Buf(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<INT64Buf> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int64 id = 1;\n    public static final int ID_FIELD_NUMBER = 1;\n    private long id_;\n    /**\n     * <code>required int64 id = 1;</code>\n     */\n    public boolean hasId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int64 id = 1;</code>\n     */\n    public long getId() {\n      return id_;\n    }\n\n    private void initFields() {\n      id_ = 0L;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt64(1, id_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, id_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.INT64Buf parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.INT64Buf parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.INT64Buf parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.INT64Buf parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.INT64Buf parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.INT64Buf parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.INT64Buf parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.INT64Buf parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.INT64Buf parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.INT64Buf parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.INT64Buf prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code INT64Buf}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.INT64BufOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_INT64Buf_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_INT64Buf_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.INT64Buf.class, cn.wildfirechat.proto.WFCMessage.INT64Buf.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.INT64Buf.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        id_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_INT64Buf_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.INT64Buf getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.INT64Buf.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.INT64Buf build() {\n        cn.wildfirechat.proto.WFCMessage.INT64Buf result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.INT64Buf buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.INT64Buf result = new cn.wildfirechat.proto.WFCMessage.INT64Buf(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.id_ = id_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.INT64Buf) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.INT64Buf)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.INT64Buf other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.INT64Buf.getDefaultInstance()) return this;\n        if (other.hasId()) {\n          setId(other.getId());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasId()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.INT64Buf parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.INT64Buf) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int64 id = 1;\n      private long id_ ;\n      /**\n       * <code>required int64 id = 1;</code>\n       */\n      public boolean hasId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int64 id = 1;</code>\n       */\n      public long getId() {\n        return id_;\n      }\n      /**\n       * <code>required int64 id = 1;</code>\n       */\n      public Builder setId(long value) {\n        bitField0_ |= 0x00000001;\n        id_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 id = 1;</code>\n       */\n      public Builder clearId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        id_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:INT64Buf)\n    }\n\n    static {\n      defaultInstance = new INT64Buf(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:INT64Buf)\n  }\n\n  public interface NotifyRecallMessageOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int64 id = 1;\n    /**\n     * <code>required int64 id = 1;</code>\n     */\n    boolean hasId();\n    /**\n     * <code>required int64 id = 1;</code>\n     */\n    long getId();\n\n    // required string from_user = 2;\n    /**\n     * <code>required string from_user = 2;</code>\n     */\n    boolean hasFromUser();\n    /**\n     * <code>required string from_user = 2;</code>\n     */\n    java.lang.String getFromUser();\n    /**\n     * <code>required string from_user = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getFromUserBytes();\n  }\n  /**\n   * Protobuf type {@code NotifyRecallMessage}\n   */\n  public static final class NotifyRecallMessage extends\n      com.google.protobuf.GeneratedMessage\n      implements NotifyRecallMessageOrBuilder {\n    // Use NotifyRecallMessage.newBuilder() to construct.\n    private NotifyRecallMessage(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private NotifyRecallMessage(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final NotifyRecallMessage defaultInstance;\n    public static NotifyRecallMessage getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public NotifyRecallMessage getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private NotifyRecallMessage(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              id_ = input.readInt64();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              fromUser_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_NotifyRecallMessage_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_NotifyRecallMessage_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage.class, cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<NotifyRecallMessage> PARSER =\n        new com.google.protobuf.AbstractParser<NotifyRecallMessage>() {\n      public NotifyRecallMessage parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new NotifyRecallMessage(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<NotifyRecallMessage> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int64 id = 1;\n    public static final int ID_FIELD_NUMBER = 1;\n    private long id_;\n    /**\n     * <code>required int64 id = 1;</code>\n     */\n    public boolean hasId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int64 id = 1;</code>\n     */\n    public long getId() {\n      return id_;\n    }\n\n    // required string from_user = 2;\n    public static final int FROM_USER_FIELD_NUMBER = 2;\n    private java.lang.Object fromUser_;\n    /**\n     * <code>required string from_user = 2;</code>\n     */\n    public boolean hasFromUser() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string from_user = 2;</code>\n     */\n    public java.lang.String getFromUser() {\n      java.lang.Object ref = fromUser_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          fromUser_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string from_user = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getFromUserBytes() {\n      java.lang.Object ref = fromUser_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        fromUser_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      id_ = 0L;\n      fromUser_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasFromUser()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt64(1, id_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getFromUserBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, id_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getFromUserBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code NotifyRecallMessage}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.NotifyRecallMessageOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_NotifyRecallMessage_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_NotifyRecallMessage_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage.class, cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        id_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        fromUser_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_NotifyRecallMessage_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage build() {\n        cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage result = new cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.id_ = id_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.fromUser_ = fromUser_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage.getDefaultInstance()) return this;\n        if (other.hasId()) {\n          setId(other.getId());\n        }\n        if (other.hasFromUser()) {\n          bitField0_ |= 0x00000002;\n          fromUser_ = other.fromUser_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasId()) {\n          \n          return false;\n        }\n        if (!hasFromUser()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.NotifyRecallMessage) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int64 id = 1;\n      private long id_ ;\n      /**\n       * <code>required int64 id = 1;</code>\n       */\n      public boolean hasId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int64 id = 1;</code>\n       */\n      public long getId() {\n        return id_;\n      }\n      /**\n       * <code>required int64 id = 1;</code>\n       */\n      public Builder setId(long value) {\n        bitField0_ |= 0x00000001;\n        id_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 id = 1;</code>\n       */\n      public Builder clearId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        id_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // required string from_user = 2;\n      private java.lang.Object fromUser_ = \"\";\n      /**\n       * <code>required string from_user = 2;</code>\n       */\n      public boolean hasFromUser() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string from_user = 2;</code>\n       */\n      public java.lang.String getFromUser() {\n        java.lang.Object ref = fromUser_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          fromUser_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string from_user = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getFromUserBytes() {\n        java.lang.Object ref = fromUser_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          fromUser_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string from_user = 2;</code>\n       */\n      public Builder setFromUser(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        fromUser_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string from_user = 2;</code>\n       */\n      public Builder clearFromUser() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        fromUser_ = getDefaultInstance().getFromUser();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string from_user = 2;</code>\n       */\n      public Builder setFromUserBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        fromUser_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:NotifyRecallMessage)\n    }\n\n    static {\n      defaultInstance = new NotifyRecallMessage(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:NotifyRecallMessage)\n  }\n\n  public interface BlackUserRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string uid = 1;\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    boolean hasUid();\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    java.lang.String getUid();\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getUidBytes();\n\n    // required int32 status = 2;\n    /**\n     * <code>required int32 status = 2;</code>\n     */\n    boolean hasStatus();\n    /**\n     * <code>required int32 status = 2;</code>\n     */\n    int getStatus();\n  }\n  /**\n   * Protobuf type {@code BlackUserRequest}\n   */\n  public static final class BlackUserRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements BlackUserRequestOrBuilder {\n    // Use BlackUserRequest.newBuilder() to construct.\n    private BlackUserRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private BlackUserRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final BlackUserRequest defaultInstance;\n    public static BlackUserRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public BlackUserRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private BlackUserRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              uid_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              status_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_BlackUserRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_BlackUserRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.BlackUserRequest.class, cn.wildfirechat.proto.WFCMessage.BlackUserRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<BlackUserRequest> PARSER =\n        new com.google.protobuf.AbstractParser<BlackUserRequest>() {\n      public BlackUserRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new BlackUserRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<BlackUserRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string uid = 1;\n    public static final int UID_FIELD_NUMBER = 1;\n    private java.lang.Object uid_;\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public boolean hasUid() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public java.lang.String getUid() {\n      java.lang.Object ref = uid_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          uid_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string uid = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getUidBytes() {\n      java.lang.Object ref = uid_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        uid_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 status = 2;\n    public static final int STATUS_FIELD_NUMBER = 2;\n    private int status_;\n    /**\n     * <code>required int32 status = 2;</code>\n     */\n    public boolean hasStatus() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 status = 2;</code>\n     */\n    public int getStatus() {\n      return status_;\n    }\n\n    private void initFields() {\n      uid_ = \"\";\n      status_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasUid()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasStatus()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, status_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getUidBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, status_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.BlackUserRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.BlackUserRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.BlackUserRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.BlackUserRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.BlackUserRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.BlackUserRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.BlackUserRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.BlackUserRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.BlackUserRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.BlackUserRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.BlackUserRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code BlackUserRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.BlackUserRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_BlackUserRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_BlackUserRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.BlackUserRequest.class, cn.wildfirechat.proto.WFCMessage.BlackUserRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.BlackUserRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        uid_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        status_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_BlackUserRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.BlackUserRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.BlackUserRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.BlackUserRequest build() {\n        cn.wildfirechat.proto.WFCMessage.BlackUserRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.BlackUserRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.BlackUserRequest result = new cn.wildfirechat.proto.WFCMessage.BlackUserRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.uid_ = uid_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.status_ = status_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.BlackUserRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.BlackUserRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.BlackUserRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.BlackUserRequest.getDefaultInstance()) return this;\n        if (other.hasUid()) {\n          bitField0_ |= 0x00000001;\n          uid_ = other.uid_;\n          onChanged();\n        }\n        if (other.hasStatus()) {\n          setStatus(other.getStatus());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasUid()) {\n          \n          return false;\n        }\n        if (!hasStatus()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.BlackUserRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.BlackUserRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string uid = 1;\n      private java.lang.Object uid_ = \"\";\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public boolean hasUid() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public java.lang.String getUid() {\n        java.lang.Object ref = uid_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          uid_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getUidBytes() {\n        java.lang.Object ref = uid_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          uid_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder setUid(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        uid_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder clearUid() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        uid_ = getDefaultInstance().getUid();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string uid = 1;</code>\n       */\n      public Builder setUidBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        uid_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 status = 2;\n      private int status_ ;\n      /**\n       * <code>required int32 status = 2;</code>\n       */\n      public boolean hasStatus() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 status = 2;</code>\n       */\n      public int getStatus() {\n        return status_;\n      }\n      /**\n       * <code>required int32 status = 2;</code>\n       */\n      public Builder setStatus(int value) {\n        bitField0_ |= 0x00000002;\n        status_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 status = 2;</code>\n       */\n      public Builder clearStatus() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        status_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:BlackUserRequest)\n    }\n\n    static {\n      defaultInstance = new BlackUserRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:BlackUserRequest)\n  }\n\n  public interface RouteRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // optional string app = 1;\n    /**\n     * <code>optional string app = 1;</code>\n     */\n    boolean hasApp();\n    /**\n     * <code>optional string app = 1;</code>\n     */\n    java.lang.String getApp();\n    /**\n     * <code>optional string app = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getAppBytes();\n\n    // optional int32 platform = 2;\n    /**\n     * <code>optional int32 platform = 2;</code>\n     */\n    boolean hasPlatform();\n    /**\n     * <code>optional int32 platform = 2;</code>\n     */\n    int getPlatform();\n\n    // optional int32 push_type = 3;\n    /**\n     * <code>optional int32 push_type = 3;</code>\n     */\n    boolean hasPushType();\n    /**\n     * <code>optional int32 push_type = 3;</code>\n     */\n    int getPushType();\n\n    // optional string device_name = 4;\n    /**\n     * <code>optional string device_name = 4;</code>\n     */\n    boolean hasDeviceName();\n    /**\n     * <code>optional string device_name = 4;</code>\n     */\n    java.lang.String getDeviceName();\n    /**\n     * <code>optional string device_name = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getDeviceNameBytes();\n\n    // optional string device_version = 5;\n    /**\n     * <code>optional string device_version = 5;</code>\n     */\n    boolean hasDeviceVersion();\n    /**\n     * <code>optional string device_version = 5;</code>\n     */\n    java.lang.String getDeviceVersion();\n    /**\n     * <code>optional string device_version = 5;</code>\n     */\n    com.google.protobuf.ByteString\n        getDeviceVersionBytes();\n\n    // optional string phone_name = 6;\n    /**\n     * <code>optional string phone_name = 6;</code>\n     */\n    boolean hasPhoneName();\n    /**\n     * <code>optional string phone_name = 6;</code>\n     */\n    java.lang.String getPhoneName();\n    /**\n     * <code>optional string phone_name = 6;</code>\n     */\n    com.google.protobuf.ByteString\n        getPhoneNameBytes();\n\n    // optional string language = 7;\n    /**\n     * <code>optional string language = 7;</code>\n     */\n    boolean hasLanguage();\n    /**\n     * <code>optional string language = 7;</code>\n     */\n    java.lang.String getLanguage();\n    /**\n     * <code>optional string language = 7;</code>\n     */\n    com.google.protobuf.ByteString\n        getLanguageBytes();\n\n    // optional string carrier_name = 8;\n    /**\n     * <code>optional string carrier_name = 8;</code>\n     */\n    boolean hasCarrierName();\n    /**\n     * <code>optional string carrier_name = 8;</code>\n     */\n    java.lang.String getCarrierName();\n    /**\n     * <code>optional string carrier_name = 8;</code>\n     */\n    com.google.protobuf.ByteString\n        getCarrierNameBytes();\n\n    // optional string app_version = 9;\n    /**\n     * <code>optional string app_version = 9;</code>\n     */\n    boolean hasAppVersion();\n    /**\n     * <code>optional string app_version = 9;</code>\n     */\n    java.lang.String getAppVersion();\n    /**\n     * <code>optional string app_version = 9;</code>\n     */\n    com.google.protobuf.ByteString\n        getAppVersionBytes();\n\n    // optional string sdk_version = 10;\n    /**\n     * <code>optional string sdk_version = 10;</code>\n     */\n    boolean hasSdkVersion();\n    /**\n     * <code>optional string sdk_version = 10;</code>\n     */\n    java.lang.String getSdkVersion();\n    /**\n     * <code>optional string sdk_version = 10;</code>\n     */\n    com.google.protobuf.ByteString\n        getSdkVersionBytes();\n  }\n  /**\n   * Protobuf type {@code RouteRequest}\n   */\n  public static final class RouteRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements RouteRequestOrBuilder {\n    // Use RouteRequest.newBuilder() to construct.\n    private RouteRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private RouteRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final RouteRequest defaultInstance;\n    public static RouteRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public RouteRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private RouteRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              app_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              platform_ = input.readInt32();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              pushType_ = input.readInt32();\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000008;\n              deviceName_ = input.readBytes();\n              break;\n            }\n            case 42: {\n              bitField0_ |= 0x00000010;\n              deviceVersion_ = input.readBytes();\n              break;\n            }\n            case 50: {\n              bitField0_ |= 0x00000020;\n              phoneName_ = input.readBytes();\n              break;\n            }\n            case 58: {\n              bitField0_ |= 0x00000040;\n              language_ = input.readBytes();\n              break;\n            }\n            case 66: {\n              bitField0_ |= 0x00000080;\n              carrierName_ = input.readBytes();\n              break;\n            }\n            case 74: {\n              bitField0_ |= 0x00000100;\n              appVersion_ = input.readBytes();\n              break;\n            }\n            case 82: {\n              bitField0_ |= 0x00000200;\n              sdkVersion_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_RouteRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_RouteRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.RouteRequest.class, cn.wildfirechat.proto.WFCMessage.RouteRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<RouteRequest> PARSER =\n        new com.google.protobuf.AbstractParser<RouteRequest>() {\n      public RouteRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new RouteRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<RouteRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // optional string app = 1;\n    public static final int APP_FIELD_NUMBER = 1;\n    private java.lang.Object app_;\n    /**\n     * <code>optional string app = 1;</code>\n     */\n    public boolean hasApp() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>optional string app = 1;</code>\n     */\n    public java.lang.String getApp() {\n      java.lang.Object ref = app_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          app_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string app = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getAppBytes() {\n      java.lang.Object ref = app_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        app_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 platform = 2;\n    public static final int PLATFORM_FIELD_NUMBER = 2;\n    private int platform_;\n    /**\n     * <code>optional int32 platform = 2;</code>\n     */\n    public boolean hasPlatform() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional int32 platform = 2;</code>\n     */\n    public int getPlatform() {\n      return platform_;\n    }\n\n    // optional int32 push_type = 3;\n    public static final int PUSH_TYPE_FIELD_NUMBER = 3;\n    private int pushType_;\n    /**\n     * <code>optional int32 push_type = 3;</code>\n     */\n    public boolean hasPushType() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional int32 push_type = 3;</code>\n     */\n    public int getPushType() {\n      return pushType_;\n    }\n\n    // optional string device_name = 4;\n    public static final int DEVICE_NAME_FIELD_NUMBER = 4;\n    private java.lang.Object deviceName_;\n    /**\n     * <code>optional string device_name = 4;</code>\n     */\n    public boolean hasDeviceName() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>optional string device_name = 4;</code>\n     */\n    public java.lang.String getDeviceName() {\n      java.lang.Object ref = deviceName_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          deviceName_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string device_name = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDeviceNameBytes() {\n      java.lang.Object ref = deviceName_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        deviceName_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string device_version = 5;\n    public static final int DEVICE_VERSION_FIELD_NUMBER = 5;\n    private java.lang.Object deviceVersion_;\n    /**\n     * <code>optional string device_version = 5;</code>\n     */\n    public boolean hasDeviceVersion() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>optional string device_version = 5;</code>\n     */\n    public java.lang.String getDeviceVersion() {\n      java.lang.Object ref = deviceVersion_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          deviceVersion_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string device_version = 5;</code>\n     */\n    public com.google.protobuf.ByteString\n        getDeviceVersionBytes() {\n      java.lang.Object ref = deviceVersion_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        deviceVersion_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string phone_name = 6;\n    public static final int PHONE_NAME_FIELD_NUMBER = 6;\n    private java.lang.Object phoneName_;\n    /**\n     * <code>optional string phone_name = 6;</code>\n     */\n    public boolean hasPhoneName() {\n      return ((bitField0_ & 0x00000020) == 0x00000020);\n    }\n    /**\n     * <code>optional string phone_name = 6;</code>\n     */\n    public java.lang.String getPhoneName() {\n      java.lang.Object ref = phoneName_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          phoneName_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string phone_name = 6;</code>\n     */\n    public com.google.protobuf.ByteString\n        getPhoneNameBytes() {\n      java.lang.Object ref = phoneName_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        phoneName_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string language = 7;\n    public static final int LANGUAGE_FIELD_NUMBER = 7;\n    private java.lang.Object language_;\n    /**\n     * <code>optional string language = 7;</code>\n     */\n    public boolean hasLanguage() {\n      return ((bitField0_ & 0x00000040) == 0x00000040);\n    }\n    /**\n     * <code>optional string language = 7;</code>\n     */\n    public java.lang.String getLanguage() {\n      java.lang.Object ref = language_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          language_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string language = 7;</code>\n     */\n    public com.google.protobuf.ByteString\n        getLanguageBytes() {\n      java.lang.Object ref = language_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        language_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string carrier_name = 8;\n    public static final int CARRIER_NAME_FIELD_NUMBER = 8;\n    private java.lang.Object carrierName_;\n    /**\n     * <code>optional string carrier_name = 8;</code>\n     */\n    public boolean hasCarrierName() {\n      return ((bitField0_ & 0x00000080) == 0x00000080);\n    }\n    /**\n     * <code>optional string carrier_name = 8;</code>\n     */\n    public java.lang.String getCarrierName() {\n      java.lang.Object ref = carrierName_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          carrierName_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string carrier_name = 8;</code>\n     */\n    public com.google.protobuf.ByteString\n        getCarrierNameBytes() {\n      java.lang.Object ref = carrierName_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        carrierName_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string app_version = 9;\n    public static final int APP_VERSION_FIELD_NUMBER = 9;\n    private java.lang.Object appVersion_;\n    /**\n     * <code>optional string app_version = 9;</code>\n     */\n    public boolean hasAppVersion() {\n      return ((bitField0_ & 0x00000100) == 0x00000100);\n    }\n    /**\n     * <code>optional string app_version = 9;</code>\n     */\n    public java.lang.String getAppVersion() {\n      java.lang.Object ref = appVersion_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          appVersion_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string app_version = 9;</code>\n     */\n    public com.google.protobuf.ByteString\n        getAppVersionBytes() {\n      java.lang.Object ref = appVersion_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        appVersion_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string sdk_version = 10;\n    public static final int SDK_VERSION_FIELD_NUMBER = 10;\n    private java.lang.Object sdkVersion_;\n    /**\n     * <code>optional string sdk_version = 10;</code>\n     */\n    public boolean hasSdkVersion() {\n      return ((bitField0_ & 0x00000200) == 0x00000200);\n    }\n    /**\n     * <code>optional string sdk_version = 10;</code>\n     */\n    public java.lang.String getSdkVersion() {\n      java.lang.Object ref = sdkVersion_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          sdkVersion_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string sdk_version = 10;</code>\n     */\n    public com.google.protobuf.ByteString\n        getSdkVersionBytes() {\n      java.lang.Object ref = sdkVersion_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        sdkVersion_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      app_ = \"\";\n      platform_ = 0;\n      pushType_ = 0;\n      deviceName_ = \"\";\n      deviceVersion_ = \"\";\n      phoneName_ = \"\";\n      language_ = \"\";\n      carrierName_ = \"\";\n      appVersion_ = \"\";\n      sdkVersion_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getAppBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, platform_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt32(3, pushType_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(4, getDeviceNameBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeBytes(5, getDeviceVersionBytes());\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        output.writeBytes(6, getPhoneNameBytes());\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        output.writeBytes(7, getLanguageBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        output.writeBytes(8, getCarrierNameBytes());\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        output.writeBytes(9, getAppVersionBytes());\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        output.writeBytes(10, getSdkVersionBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getAppBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, platform_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(3, pushType_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, getDeviceNameBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5, getDeviceVersionBytes());\n      }\n      if (((bitField0_ & 0x00000020) == 0x00000020)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(6, getPhoneNameBytes());\n      }\n      if (((bitField0_ & 0x00000040) == 0x00000040)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(7, getLanguageBytes());\n      }\n      if (((bitField0_ & 0x00000080) == 0x00000080)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(8, getCarrierNameBytes());\n      }\n      if (((bitField0_ & 0x00000100) == 0x00000100)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(9, getAppVersionBytes());\n      }\n      if (((bitField0_ & 0x00000200) == 0x00000200)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(10, getSdkVersionBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.RouteRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.RouteRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code RouteRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.RouteRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_RouteRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_RouteRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.RouteRequest.class, cn.wildfirechat.proto.WFCMessage.RouteRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.RouteRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        app_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        platform_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        pushType_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        deviceName_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        deviceVersion_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000010);\n        phoneName_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000020);\n        language_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000040);\n        carrierName_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000080);\n        appVersion_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000100);\n        sdkVersion_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000200);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_RouteRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.RouteRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.RouteRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.RouteRequest build() {\n        cn.wildfirechat.proto.WFCMessage.RouteRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.RouteRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.RouteRequest result = new cn.wildfirechat.proto.WFCMessage.RouteRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.app_ = app_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.platform_ = platform_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.pushType_ = pushType_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.deviceName_ = deviceName_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.deviceVersion_ = deviceVersion_;\n        if (((from_bitField0_ & 0x00000020) == 0x00000020)) {\n          to_bitField0_ |= 0x00000020;\n        }\n        result.phoneName_ = phoneName_;\n        if (((from_bitField0_ & 0x00000040) == 0x00000040)) {\n          to_bitField0_ |= 0x00000040;\n        }\n        result.language_ = language_;\n        if (((from_bitField0_ & 0x00000080) == 0x00000080)) {\n          to_bitField0_ |= 0x00000080;\n        }\n        result.carrierName_ = carrierName_;\n        if (((from_bitField0_ & 0x00000100) == 0x00000100)) {\n          to_bitField0_ |= 0x00000100;\n        }\n        result.appVersion_ = appVersion_;\n        if (((from_bitField0_ & 0x00000200) == 0x00000200)) {\n          to_bitField0_ |= 0x00000200;\n        }\n        result.sdkVersion_ = sdkVersion_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.RouteRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.RouteRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.RouteRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.RouteRequest.getDefaultInstance()) return this;\n        if (other.hasApp()) {\n          bitField0_ |= 0x00000001;\n          app_ = other.app_;\n          onChanged();\n        }\n        if (other.hasPlatform()) {\n          setPlatform(other.getPlatform());\n        }\n        if (other.hasPushType()) {\n          setPushType(other.getPushType());\n        }\n        if (other.hasDeviceName()) {\n          bitField0_ |= 0x00000008;\n          deviceName_ = other.deviceName_;\n          onChanged();\n        }\n        if (other.hasDeviceVersion()) {\n          bitField0_ |= 0x00000010;\n          deviceVersion_ = other.deviceVersion_;\n          onChanged();\n        }\n        if (other.hasPhoneName()) {\n          bitField0_ |= 0x00000020;\n          phoneName_ = other.phoneName_;\n          onChanged();\n        }\n        if (other.hasLanguage()) {\n          bitField0_ |= 0x00000040;\n          language_ = other.language_;\n          onChanged();\n        }\n        if (other.hasCarrierName()) {\n          bitField0_ |= 0x00000080;\n          carrierName_ = other.carrierName_;\n          onChanged();\n        }\n        if (other.hasAppVersion()) {\n          bitField0_ |= 0x00000100;\n          appVersion_ = other.appVersion_;\n          onChanged();\n        }\n        if (other.hasSdkVersion()) {\n          bitField0_ |= 0x00000200;\n          sdkVersion_ = other.sdkVersion_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.RouteRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.RouteRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // optional string app = 1;\n      private java.lang.Object app_ = \"\";\n      /**\n       * <code>optional string app = 1;</code>\n       */\n      public boolean hasApp() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>optional string app = 1;</code>\n       */\n      public java.lang.String getApp() {\n        java.lang.Object ref = app_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          app_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string app = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getAppBytes() {\n        java.lang.Object ref = app_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          app_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string app = 1;</code>\n       */\n      public Builder setApp(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        app_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string app = 1;</code>\n       */\n      public Builder clearApp() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        app_ = getDefaultInstance().getApp();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string app = 1;</code>\n       */\n      public Builder setAppBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        app_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 platform = 2;\n      private int platform_ ;\n      /**\n       * <code>optional int32 platform = 2;</code>\n       */\n      public boolean hasPlatform() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional int32 platform = 2;</code>\n       */\n      public int getPlatform() {\n        return platform_;\n      }\n      /**\n       * <code>optional int32 platform = 2;</code>\n       */\n      public Builder setPlatform(int value) {\n        bitField0_ |= 0x00000002;\n        platform_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 platform = 2;</code>\n       */\n      public Builder clearPlatform() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        platform_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 push_type = 3;\n      private int pushType_ ;\n      /**\n       * <code>optional int32 push_type = 3;</code>\n       */\n      public boolean hasPushType() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional int32 push_type = 3;</code>\n       */\n      public int getPushType() {\n        return pushType_;\n      }\n      /**\n       * <code>optional int32 push_type = 3;</code>\n       */\n      public Builder setPushType(int value) {\n        bitField0_ |= 0x00000004;\n        pushType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 push_type = 3;</code>\n       */\n      public Builder clearPushType() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        pushType_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // optional string device_name = 4;\n      private java.lang.Object deviceName_ = \"\";\n      /**\n       * <code>optional string device_name = 4;</code>\n       */\n      public boolean hasDeviceName() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>optional string device_name = 4;</code>\n       */\n      public java.lang.String getDeviceName() {\n        java.lang.Object ref = deviceName_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          deviceName_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string device_name = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDeviceNameBytes() {\n        java.lang.Object ref = deviceName_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          deviceName_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string device_name = 4;</code>\n       */\n      public Builder setDeviceName(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        deviceName_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string device_name = 4;</code>\n       */\n      public Builder clearDeviceName() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        deviceName_ = getDefaultInstance().getDeviceName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string device_name = 4;</code>\n       */\n      public Builder setDeviceNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        deviceName_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string device_version = 5;\n      private java.lang.Object deviceVersion_ = \"\";\n      /**\n       * <code>optional string device_version = 5;</code>\n       */\n      public boolean hasDeviceVersion() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>optional string device_version = 5;</code>\n       */\n      public java.lang.String getDeviceVersion() {\n        java.lang.Object ref = deviceVersion_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          deviceVersion_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string device_version = 5;</code>\n       */\n      public com.google.protobuf.ByteString\n          getDeviceVersionBytes() {\n        java.lang.Object ref = deviceVersion_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          deviceVersion_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string device_version = 5;</code>\n       */\n      public Builder setDeviceVersion(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        deviceVersion_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string device_version = 5;</code>\n       */\n      public Builder clearDeviceVersion() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        deviceVersion_ = getDefaultInstance().getDeviceVersion();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string device_version = 5;</code>\n       */\n      public Builder setDeviceVersionBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        deviceVersion_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string phone_name = 6;\n      private java.lang.Object phoneName_ = \"\";\n      /**\n       * <code>optional string phone_name = 6;</code>\n       */\n      public boolean hasPhoneName() {\n        return ((bitField0_ & 0x00000020) == 0x00000020);\n      }\n      /**\n       * <code>optional string phone_name = 6;</code>\n       */\n      public java.lang.String getPhoneName() {\n        java.lang.Object ref = phoneName_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          phoneName_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string phone_name = 6;</code>\n       */\n      public com.google.protobuf.ByteString\n          getPhoneNameBytes() {\n        java.lang.Object ref = phoneName_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          phoneName_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string phone_name = 6;</code>\n       */\n      public Builder setPhoneName(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        phoneName_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string phone_name = 6;</code>\n       */\n      public Builder clearPhoneName() {\n        bitField0_ = (bitField0_ & ~0x00000020);\n        phoneName_ = getDefaultInstance().getPhoneName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string phone_name = 6;</code>\n       */\n      public Builder setPhoneNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000020;\n        phoneName_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string language = 7;\n      private java.lang.Object language_ = \"\";\n      /**\n       * <code>optional string language = 7;</code>\n       */\n      public boolean hasLanguage() {\n        return ((bitField0_ & 0x00000040) == 0x00000040);\n      }\n      /**\n       * <code>optional string language = 7;</code>\n       */\n      public java.lang.String getLanguage() {\n        java.lang.Object ref = language_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          language_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string language = 7;</code>\n       */\n      public com.google.protobuf.ByteString\n          getLanguageBytes() {\n        java.lang.Object ref = language_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          language_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string language = 7;</code>\n       */\n      public Builder setLanguage(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        language_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string language = 7;</code>\n       */\n      public Builder clearLanguage() {\n        bitField0_ = (bitField0_ & ~0x00000040);\n        language_ = getDefaultInstance().getLanguage();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string language = 7;</code>\n       */\n      public Builder setLanguageBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000040;\n        language_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string carrier_name = 8;\n      private java.lang.Object carrierName_ = \"\";\n      /**\n       * <code>optional string carrier_name = 8;</code>\n       */\n      public boolean hasCarrierName() {\n        return ((bitField0_ & 0x00000080) == 0x00000080);\n      }\n      /**\n       * <code>optional string carrier_name = 8;</code>\n       */\n      public java.lang.String getCarrierName() {\n        java.lang.Object ref = carrierName_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          carrierName_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string carrier_name = 8;</code>\n       */\n      public com.google.protobuf.ByteString\n          getCarrierNameBytes() {\n        java.lang.Object ref = carrierName_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          carrierName_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string carrier_name = 8;</code>\n       */\n      public Builder setCarrierName(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000080;\n        carrierName_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string carrier_name = 8;</code>\n       */\n      public Builder clearCarrierName() {\n        bitField0_ = (bitField0_ & ~0x00000080);\n        carrierName_ = getDefaultInstance().getCarrierName();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string carrier_name = 8;</code>\n       */\n      public Builder setCarrierNameBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000080;\n        carrierName_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string app_version = 9;\n      private java.lang.Object appVersion_ = \"\";\n      /**\n       * <code>optional string app_version = 9;</code>\n       */\n      public boolean hasAppVersion() {\n        return ((bitField0_ & 0x00000100) == 0x00000100);\n      }\n      /**\n       * <code>optional string app_version = 9;</code>\n       */\n      public java.lang.String getAppVersion() {\n        java.lang.Object ref = appVersion_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          appVersion_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string app_version = 9;</code>\n       */\n      public com.google.protobuf.ByteString\n          getAppVersionBytes() {\n        java.lang.Object ref = appVersion_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          appVersion_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string app_version = 9;</code>\n       */\n      public Builder setAppVersion(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000100;\n        appVersion_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string app_version = 9;</code>\n       */\n      public Builder clearAppVersion() {\n        bitField0_ = (bitField0_ & ~0x00000100);\n        appVersion_ = getDefaultInstance().getAppVersion();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string app_version = 9;</code>\n       */\n      public Builder setAppVersionBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000100;\n        appVersion_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string sdk_version = 10;\n      private java.lang.Object sdkVersion_ = \"\";\n      /**\n       * <code>optional string sdk_version = 10;</code>\n       */\n      public boolean hasSdkVersion() {\n        return ((bitField0_ & 0x00000200) == 0x00000200);\n      }\n      /**\n       * <code>optional string sdk_version = 10;</code>\n       */\n      public java.lang.String getSdkVersion() {\n        java.lang.Object ref = sdkVersion_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          sdkVersion_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string sdk_version = 10;</code>\n       */\n      public com.google.protobuf.ByteString\n          getSdkVersionBytes() {\n        java.lang.Object ref = sdkVersion_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          sdkVersion_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string sdk_version = 10;</code>\n       */\n      public Builder setSdkVersion(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000200;\n        sdkVersion_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string sdk_version = 10;</code>\n       */\n      public Builder clearSdkVersion() {\n        bitField0_ = (bitField0_ & ~0x00000200);\n        sdkVersion_ = getDefaultInstance().getSdkVersion();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string sdk_version = 10;</code>\n       */\n      public Builder setSdkVersionBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000200;\n        sdkVersion_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:RouteRequest)\n    }\n\n    static {\n      defaultInstance = new RouteRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:RouteRequest)\n  }\n\n  public interface RouteResponseOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string host = 1;\n    /**\n     * <code>required string host = 1;</code>\n     */\n    boolean hasHost();\n    /**\n     * <code>required string host = 1;</code>\n     */\n    java.lang.String getHost();\n    /**\n     * <code>required string host = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getHostBytes();\n\n    // required int32 long_port = 2;\n    /**\n     * <code>required int32 long_port = 2;</code>\n     */\n    boolean hasLongPort();\n    /**\n     * <code>required int32 long_port = 2;</code>\n     */\n    int getLongPort();\n\n    // required int32 short_port = 3;\n    /**\n     * <code>required int32 short_port = 3;</code>\n     */\n    boolean hasShortPort();\n    /**\n     * <code>required int32 short_port = 3;</code>\n     */\n    int getShortPort();\n  }\n  /**\n   * Protobuf type {@code RouteResponse}\n   */\n  public static final class RouteResponse extends\n      com.google.protobuf.GeneratedMessage\n      implements RouteResponseOrBuilder {\n    // Use RouteResponse.newBuilder() to construct.\n    private RouteResponse(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private RouteResponse(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final RouteResponse defaultInstance;\n    public static RouteResponse getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public RouteResponse getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private RouteResponse(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              host_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              longPort_ = input.readInt32();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              shortPort_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_RouteResponse_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_RouteResponse_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.RouteResponse.class, cn.wildfirechat.proto.WFCMessage.RouteResponse.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<RouteResponse> PARSER =\n        new com.google.protobuf.AbstractParser<RouteResponse>() {\n      public RouteResponse parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new RouteResponse(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<RouteResponse> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string host = 1;\n    public static final int HOST_FIELD_NUMBER = 1;\n    private java.lang.Object host_;\n    /**\n     * <code>required string host = 1;</code>\n     */\n    public boolean hasHost() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string host = 1;</code>\n     */\n    public java.lang.String getHost() {\n      java.lang.Object ref = host_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          host_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string host = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getHostBytes() {\n      java.lang.Object ref = host_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        host_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 long_port = 2;\n    public static final int LONG_PORT_FIELD_NUMBER = 2;\n    private int longPort_;\n    /**\n     * <code>required int32 long_port = 2;</code>\n     */\n    public boolean hasLongPort() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 long_port = 2;</code>\n     */\n    public int getLongPort() {\n      return longPort_;\n    }\n\n    // required int32 short_port = 3;\n    public static final int SHORT_PORT_FIELD_NUMBER = 3;\n    private int shortPort_;\n    /**\n     * <code>required int32 short_port = 3;</code>\n     */\n    public boolean hasShortPort() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required int32 short_port = 3;</code>\n     */\n    public int getShortPort() {\n      return shortPort_;\n    }\n\n    private void initFields() {\n      host_ = \"\";\n      longPort_ = 0;\n      shortPort_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasHost()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasLongPort()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasShortPort()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getHostBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, longPort_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt32(3, shortPort_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getHostBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, longPort_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(3, shortPort_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.RouteResponse parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteResponse parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteResponse parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteResponse parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteResponse parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteResponse parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteResponse parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteResponse parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteResponse parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RouteResponse parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.RouteResponse prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code RouteResponse}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.RouteResponseOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_RouteResponse_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_RouteResponse_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.RouteResponse.class, cn.wildfirechat.proto.WFCMessage.RouteResponse.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.RouteResponse.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        host_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        longPort_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        shortPort_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_RouteResponse_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.RouteResponse getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.RouteResponse.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.RouteResponse build() {\n        cn.wildfirechat.proto.WFCMessage.RouteResponse result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.RouteResponse buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.RouteResponse result = new cn.wildfirechat.proto.WFCMessage.RouteResponse(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.host_ = host_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.longPort_ = longPort_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.shortPort_ = shortPort_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.RouteResponse) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.RouteResponse)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.RouteResponse other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.RouteResponse.getDefaultInstance()) return this;\n        if (other.hasHost()) {\n          bitField0_ |= 0x00000001;\n          host_ = other.host_;\n          onChanged();\n        }\n        if (other.hasLongPort()) {\n          setLongPort(other.getLongPort());\n        }\n        if (other.hasShortPort()) {\n          setShortPort(other.getShortPort());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasHost()) {\n          \n          return false;\n        }\n        if (!hasLongPort()) {\n          \n          return false;\n        }\n        if (!hasShortPort()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.RouteResponse parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.RouteResponse) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string host = 1;\n      private java.lang.Object host_ = \"\";\n      /**\n       * <code>required string host = 1;</code>\n       */\n      public boolean hasHost() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string host = 1;</code>\n       */\n      public java.lang.String getHost() {\n        java.lang.Object ref = host_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          host_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string host = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getHostBytes() {\n        java.lang.Object ref = host_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          host_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string host = 1;</code>\n       */\n      public Builder setHost(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        host_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string host = 1;</code>\n       */\n      public Builder clearHost() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        host_ = getDefaultInstance().getHost();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string host = 1;</code>\n       */\n      public Builder setHostBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        host_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 long_port = 2;\n      private int longPort_ ;\n      /**\n       * <code>required int32 long_port = 2;</code>\n       */\n      public boolean hasLongPort() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 long_port = 2;</code>\n       */\n      public int getLongPort() {\n        return longPort_;\n      }\n      /**\n       * <code>required int32 long_port = 2;</code>\n       */\n      public Builder setLongPort(int value) {\n        bitField0_ |= 0x00000002;\n        longPort_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 long_port = 2;</code>\n       */\n      public Builder clearLongPort() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        longPort_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required int32 short_port = 3;\n      private int shortPort_ ;\n      /**\n       * <code>required int32 short_port = 3;</code>\n       */\n      public boolean hasShortPort() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required int32 short_port = 3;</code>\n       */\n      public int getShortPort() {\n        return shortPort_;\n      }\n      /**\n       * <code>required int32 short_port = 3;</code>\n       */\n      public Builder setShortPort(int value) {\n        bitField0_ |= 0x00000004;\n        shortPort_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 short_port = 3;</code>\n       */\n      public Builder clearShortPort() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        shortPort_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:RouteResponse)\n    }\n\n    static {\n      defaultInstance = new RouteResponse(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:RouteResponse)\n  }\n\n  public interface GetTokenRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string user_id = 1;\n    /**\n     * <code>required string user_id = 1;</code>\n     */\n    boolean hasUserId();\n    /**\n     * <code>required string user_id = 1;</code>\n     */\n    java.lang.String getUserId();\n    /**\n     * <code>required string user_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getUserIdBytes();\n\n    // required string client_id = 2;\n    /**\n     * <code>required string client_id = 2;</code>\n     */\n    boolean hasClientId();\n    /**\n     * <code>required string client_id = 2;</code>\n     */\n    java.lang.String getClientId();\n    /**\n     * <code>required string client_id = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getClientIdBytes();\n\n    // optional int32 platform = 3;\n    /**\n     * <code>optional int32 platform = 3;</code>\n     */\n    boolean hasPlatform();\n    /**\n     * <code>optional int32 platform = 3;</code>\n     */\n    int getPlatform();\n  }\n  /**\n   * Protobuf type {@code GetTokenRequest}\n   */\n  public static final class GetTokenRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements GetTokenRequestOrBuilder {\n    // Use GetTokenRequest.newBuilder() to construct.\n    private GetTokenRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private GetTokenRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final GetTokenRequest defaultInstance;\n    public static GetTokenRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public GetTokenRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private GetTokenRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              userId_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              clientId_ = input.readBytes();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              platform_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetTokenRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_GetTokenRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.GetTokenRequest.class, cn.wildfirechat.proto.WFCMessage.GetTokenRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<GetTokenRequest> PARSER =\n        new com.google.protobuf.AbstractParser<GetTokenRequest>() {\n      public GetTokenRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new GetTokenRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<GetTokenRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string user_id = 1;\n    public static final int USER_ID_FIELD_NUMBER = 1;\n    private java.lang.Object userId_;\n    /**\n     * <code>required string user_id = 1;</code>\n     */\n    public boolean hasUserId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string user_id = 1;</code>\n     */\n    public java.lang.String getUserId() {\n      java.lang.Object ref = userId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          userId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string user_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getUserIdBytes() {\n      java.lang.Object ref = userId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        userId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string client_id = 2;\n    public static final int CLIENT_ID_FIELD_NUMBER = 2;\n    private java.lang.Object clientId_;\n    /**\n     * <code>required string client_id = 2;</code>\n     */\n    public boolean hasClientId() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required string client_id = 2;</code>\n     */\n    public java.lang.String getClientId() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          clientId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string client_id = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getClientIdBytes() {\n      java.lang.Object ref = clientId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        clientId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional int32 platform = 3;\n    public static final int PLATFORM_FIELD_NUMBER = 3;\n    private int platform_;\n    /**\n     * <code>optional int32 platform = 3;</code>\n     */\n    public boolean hasPlatform() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>optional int32 platform = 3;</code>\n     */\n    public int getPlatform() {\n      return platform_;\n    }\n\n    private void initFields() {\n      userId_ = \"\";\n      clientId_ = \"\";\n      platform_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasUserId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasClientId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getUserIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getClientIdBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt32(3, platform_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getUserIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getClientIdBytes());\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(3, platform_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.GetTokenRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetTokenRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetTokenRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetTokenRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetTokenRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetTokenRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetTokenRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetTokenRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetTokenRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.GetTokenRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.GetTokenRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code GetTokenRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.GetTokenRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetTokenRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetTokenRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.GetTokenRequest.class, cn.wildfirechat.proto.WFCMessage.GetTokenRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.GetTokenRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        userId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        clientId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        platform_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_GetTokenRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetTokenRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.GetTokenRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetTokenRequest build() {\n        cn.wildfirechat.proto.WFCMessage.GetTokenRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.GetTokenRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.GetTokenRequest result = new cn.wildfirechat.proto.WFCMessage.GetTokenRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.userId_ = userId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.clientId_ = clientId_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.platform_ = platform_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.GetTokenRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.GetTokenRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.GetTokenRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.GetTokenRequest.getDefaultInstance()) return this;\n        if (other.hasUserId()) {\n          bitField0_ |= 0x00000001;\n          userId_ = other.userId_;\n          onChanged();\n        }\n        if (other.hasClientId()) {\n          bitField0_ |= 0x00000002;\n          clientId_ = other.clientId_;\n          onChanged();\n        }\n        if (other.hasPlatform()) {\n          setPlatform(other.getPlatform());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasUserId()) {\n          \n          return false;\n        }\n        if (!hasClientId()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.GetTokenRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.GetTokenRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string user_id = 1;\n      private java.lang.Object userId_ = \"\";\n      /**\n       * <code>required string user_id = 1;</code>\n       */\n      public boolean hasUserId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string user_id = 1;</code>\n       */\n      public java.lang.String getUserId() {\n        java.lang.Object ref = userId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          userId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string user_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getUserIdBytes() {\n        java.lang.Object ref = userId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          userId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string user_id = 1;</code>\n       */\n      public Builder setUserId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        userId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string user_id = 1;</code>\n       */\n      public Builder clearUserId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        userId_ = getDefaultInstance().getUserId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string user_id = 1;</code>\n       */\n      public Builder setUserIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        userId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string client_id = 2;\n      private java.lang.Object clientId_ = \"\";\n      /**\n       * <code>required string client_id = 2;</code>\n       */\n      public boolean hasClientId() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required string client_id = 2;</code>\n       */\n      public java.lang.String getClientId() {\n        java.lang.Object ref = clientId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          clientId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string client_id = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getClientIdBytes() {\n        java.lang.Object ref = clientId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          clientId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string client_id = 2;</code>\n       */\n      public Builder setClientId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string client_id = 2;</code>\n       */\n      public Builder clearClientId() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        clientId_ = getDefaultInstance().getClientId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string client_id = 2;</code>\n       */\n      public Builder setClientIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        clientId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional int32 platform = 3;\n      private int platform_ ;\n      /**\n       * <code>optional int32 platform = 3;</code>\n       */\n      public boolean hasPlatform() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>optional int32 platform = 3;</code>\n       */\n      public int getPlatform() {\n        return platform_;\n      }\n      /**\n       * <code>optional int32 platform = 3;</code>\n       */\n      public Builder setPlatform(int value) {\n        bitField0_ |= 0x00000004;\n        platform_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional int32 platform = 3;</code>\n       */\n      public Builder clearPlatform() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        platform_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:GetTokenRequest)\n    }\n\n    static {\n      defaultInstance = new GetTokenRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:GetTokenRequest)\n  }\n\n  public interface LoadRemoteMessagesOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required .Conversation conversation = 1;\n    /**\n     * <code>required .Conversation conversation = 1;</code>\n     */\n    boolean hasConversation();\n    /**\n     * <code>required .Conversation conversation = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.Conversation getConversation();\n    /**\n     * <code>required .Conversation conversation = 1;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder getConversationOrBuilder();\n\n    // required int64 before_uid = 2;\n    /**\n     * <code>required int64 before_uid = 2;</code>\n     */\n    boolean hasBeforeUid();\n    /**\n     * <code>required int64 before_uid = 2;</code>\n     */\n    long getBeforeUid();\n\n    // required int32 count = 3;\n    /**\n     * <code>required int32 count = 3;</code>\n     */\n    boolean hasCount();\n    /**\n     * <code>required int32 count = 3;</code>\n     */\n    int getCount();\n\n    // repeated int32 content_type = 4;\n    /**\n     * <code>repeated int32 content_type = 4;</code>\n     */\n    java.util.List<java.lang.Integer> getContentTypeList();\n    /**\n     * <code>repeated int32 content_type = 4;</code>\n     */\n    int getContentTypeCount();\n    /**\n     * <code>repeated int32 content_type = 4;</code>\n     */\n    int getContentType(int index);\n  }\n  /**\n   * Protobuf type {@code LoadRemoteMessages}\n   */\n  public static final class LoadRemoteMessages extends\n      com.google.protobuf.GeneratedMessage\n      implements LoadRemoteMessagesOrBuilder {\n    // Use LoadRemoteMessages.newBuilder() to construct.\n    private LoadRemoteMessages(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private LoadRemoteMessages(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final LoadRemoteMessages defaultInstance;\n    public static LoadRemoteMessages getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public LoadRemoteMessages getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private LoadRemoteMessages(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              cn.wildfirechat.proto.WFCMessage.Conversation.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000001) == 0x00000001)) {\n                subBuilder = conversation_.toBuilder();\n              }\n              conversation_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.Conversation.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(conversation_);\n                conversation_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000001;\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              beforeUid_ = input.readInt64();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              count_ = input.readInt32();\n              break;\n            }\n            case 32: {\n              if (!((mutable_bitField0_ & 0x00000008) == 0x00000008)) {\n                contentType_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000008;\n              }\n              contentType_.add(input.readInt32());\n              break;\n            }\n            case 34: {\n              int length = input.readRawVarint32();\n              int limit = input.pushLimit(length);\n              if (!((mutable_bitField0_ & 0x00000008) == 0x00000008) && input.getBytesUntilLimit() > 0) {\n                contentType_ = new java.util.ArrayList<java.lang.Integer>();\n                mutable_bitField0_ |= 0x00000008;\n              }\n              while (input.getBytesUntilLimit() > 0) {\n                contentType_.add(input.readInt32());\n              }\n              input.popLimit(limit);\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000008) == 0x00000008)) {\n          contentType_ = java.util.Collections.unmodifiableList(contentType_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_LoadRemoteMessages_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_LoadRemoteMessages_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages.class, cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<LoadRemoteMessages> PARSER =\n        new com.google.protobuf.AbstractParser<LoadRemoteMessages>() {\n      public LoadRemoteMessages parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new LoadRemoteMessages(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<LoadRemoteMessages> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required .Conversation conversation = 1;\n    public static final int CONVERSATION_FIELD_NUMBER = 1;\n    private cn.wildfirechat.proto.WFCMessage.Conversation conversation_;\n    /**\n     * <code>required .Conversation conversation = 1;</code>\n     */\n    public boolean hasConversation() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required .Conversation conversation = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.Conversation getConversation() {\n      return conversation_;\n    }\n    /**\n     * <code>required .Conversation conversation = 1;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder getConversationOrBuilder() {\n      return conversation_;\n    }\n\n    // required int64 before_uid = 2;\n    public static final int BEFORE_UID_FIELD_NUMBER = 2;\n    private long beforeUid_;\n    /**\n     * <code>required int64 before_uid = 2;</code>\n     */\n    public boolean hasBeforeUid() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int64 before_uid = 2;</code>\n     */\n    public long getBeforeUid() {\n      return beforeUid_;\n    }\n\n    // required int32 count = 3;\n    public static final int COUNT_FIELD_NUMBER = 3;\n    private int count_;\n    /**\n     * <code>required int32 count = 3;</code>\n     */\n    public boolean hasCount() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required int32 count = 3;</code>\n     */\n    public int getCount() {\n      return count_;\n    }\n\n    // repeated int32 content_type = 4;\n    public static final int CONTENT_TYPE_FIELD_NUMBER = 4;\n    private java.util.List<java.lang.Integer> contentType_;\n    /**\n     * <code>repeated int32 content_type = 4;</code>\n     */\n    public java.util.List<java.lang.Integer>\n        getContentTypeList() {\n      return contentType_;\n    }\n    /**\n     * <code>repeated int32 content_type = 4;</code>\n     */\n    public int getContentTypeCount() {\n      return contentType_.size();\n    }\n    /**\n     * <code>repeated int32 content_type = 4;</code>\n     */\n    public int getContentType(int index) {\n      return contentType_.get(index);\n    }\n\n    private void initFields() {\n      conversation_ = cn.wildfirechat.proto.WFCMessage.Conversation.getDefaultInstance();\n      beforeUid_ = 0L;\n      count_ = 0;\n      contentType_ = java.util.Collections.emptyList();\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasConversation()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasBeforeUid()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasCount()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!getConversation().isInitialized()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeMessage(1, conversation_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt64(2, beforeUid_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt32(3, count_);\n      }\n      for (int i = 0; i < contentType_.size(); i++) {\n        output.writeInt32(4, contentType_.get(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(1, conversation_);\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(2, beforeUid_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(3, count_);\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < contentType_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeInt32SizeNoTag(contentType_.get(i));\n        }\n        size += dataSize;\n        size += 1 * getContentTypeList().size();\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code LoadRemoteMessages}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.LoadRemoteMessagesOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_LoadRemoteMessages_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_LoadRemoteMessages_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages.class, cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getConversationFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        if (conversationBuilder_ == null) {\n          conversation_ = cn.wildfirechat.proto.WFCMessage.Conversation.getDefaultInstance();\n        } else {\n          conversationBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000001);\n        beforeUid_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        count_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        contentType_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_LoadRemoteMessages_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages build() {\n        cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages result = new cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        if (conversationBuilder_ == null) {\n          result.conversation_ = conversation_;\n        } else {\n          result.conversation_ = conversationBuilder_.build();\n        }\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.beforeUid_ = beforeUid_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.count_ = count_;\n        if (((bitField0_ & 0x00000008) == 0x00000008)) {\n          contentType_ = java.util.Collections.unmodifiableList(contentType_);\n          bitField0_ = (bitField0_ & ~0x00000008);\n        }\n        result.contentType_ = contentType_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages.getDefaultInstance()) return this;\n        if (other.hasConversation()) {\n          mergeConversation(other.getConversation());\n        }\n        if (other.hasBeforeUid()) {\n          setBeforeUid(other.getBeforeUid());\n        }\n        if (other.hasCount()) {\n          setCount(other.getCount());\n        }\n        if (!other.contentType_.isEmpty()) {\n          if (contentType_.isEmpty()) {\n            contentType_ = other.contentType_;\n            bitField0_ = (bitField0_ & ~0x00000008);\n          } else {\n            ensureContentTypeIsMutable();\n            contentType_.addAll(other.contentType_);\n          }\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasConversation()) {\n          \n          return false;\n        }\n        if (!hasBeforeUid()) {\n          \n          return false;\n        }\n        if (!hasCount()) {\n          \n          return false;\n        }\n        if (!getConversation().isInitialized()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.LoadRemoteMessages) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required .Conversation conversation = 1;\n      private cn.wildfirechat.proto.WFCMessage.Conversation conversation_ = cn.wildfirechat.proto.WFCMessage.Conversation.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.Conversation, cn.wildfirechat.proto.WFCMessage.Conversation.Builder, cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder> conversationBuilder_;\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public boolean hasConversation() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Conversation getConversation() {\n        if (conversationBuilder_ == null) {\n          return conversation_;\n        } else {\n          return conversationBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public Builder setConversation(cn.wildfirechat.proto.WFCMessage.Conversation value) {\n        if (conversationBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          conversation_ = value;\n          onChanged();\n        } else {\n          conversationBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public Builder setConversation(\n          cn.wildfirechat.proto.WFCMessage.Conversation.Builder builderForValue) {\n        if (conversationBuilder_ == null) {\n          conversation_ = builderForValue.build();\n          onChanged();\n        } else {\n          conversationBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public Builder mergeConversation(cn.wildfirechat.proto.WFCMessage.Conversation value) {\n        if (conversationBuilder_ == null) {\n          if (((bitField0_ & 0x00000001) == 0x00000001) &&\n              conversation_ != cn.wildfirechat.proto.WFCMessage.Conversation.getDefaultInstance()) {\n            conversation_ =\n              cn.wildfirechat.proto.WFCMessage.Conversation.newBuilder(conversation_).mergeFrom(value).buildPartial();\n          } else {\n            conversation_ = value;\n          }\n          onChanged();\n        } else {\n          conversationBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000001;\n        return this;\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public Builder clearConversation() {\n        if (conversationBuilder_ == null) {\n          conversation_ = cn.wildfirechat.proto.WFCMessage.Conversation.getDefaultInstance();\n          onChanged();\n        } else {\n          conversationBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000001);\n        return this;\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.Conversation.Builder getConversationBuilder() {\n        bitField0_ |= 0x00000001;\n        onChanged();\n        return getConversationFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder getConversationOrBuilder() {\n        if (conversationBuilder_ != null) {\n          return conversationBuilder_.getMessageOrBuilder();\n        } else {\n          return conversation_;\n        }\n      }\n      /**\n       * <code>required .Conversation conversation = 1;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.Conversation, cn.wildfirechat.proto.WFCMessage.Conversation.Builder, cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder> \n          getConversationFieldBuilder() {\n        if (conversationBuilder_ == null) {\n          conversationBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.Conversation, cn.wildfirechat.proto.WFCMessage.Conversation.Builder, cn.wildfirechat.proto.WFCMessage.ConversationOrBuilder>(\n                  conversation_,\n                  getParentForChildren(),\n                  isClean());\n          conversation_ = null;\n        }\n        return conversationBuilder_;\n      }\n\n      // required int64 before_uid = 2;\n      private long beforeUid_ ;\n      /**\n       * <code>required int64 before_uid = 2;</code>\n       */\n      public boolean hasBeforeUid() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int64 before_uid = 2;</code>\n       */\n      public long getBeforeUid() {\n        return beforeUid_;\n      }\n      /**\n       * <code>required int64 before_uid = 2;</code>\n       */\n      public Builder setBeforeUid(long value) {\n        bitField0_ |= 0x00000002;\n        beforeUid_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 before_uid = 2;</code>\n       */\n      public Builder clearBeforeUid() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        beforeUid_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // required int32 count = 3;\n      private int count_ ;\n      /**\n       * <code>required int32 count = 3;</code>\n       */\n      public boolean hasCount() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required int32 count = 3;</code>\n       */\n      public int getCount() {\n        return count_;\n      }\n      /**\n       * <code>required int32 count = 3;</code>\n       */\n      public Builder setCount(int value) {\n        bitField0_ |= 0x00000004;\n        count_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 count = 3;</code>\n       */\n      public Builder clearCount() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        count_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // repeated int32 content_type = 4;\n      private java.util.List<java.lang.Integer> contentType_ = java.util.Collections.emptyList();\n      private void ensureContentTypeIsMutable() {\n        if (!((bitField0_ & 0x00000008) == 0x00000008)) {\n          contentType_ = new java.util.ArrayList<java.lang.Integer>(contentType_);\n          bitField0_ |= 0x00000008;\n         }\n      }\n      /**\n       * <code>repeated int32 content_type = 4;</code>\n       */\n      public java.util.List<java.lang.Integer>\n          getContentTypeList() {\n        return java.util.Collections.unmodifiableList(contentType_);\n      }\n      /**\n       * <code>repeated int32 content_type = 4;</code>\n       */\n      public int getContentTypeCount() {\n        return contentType_.size();\n      }\n      /**\n       * <code>repeated int32 content_type = 4;</code>\n       */\n      public int getContentType(int index) {\n        return contentType_.get(index);\n      }\n      /**\n       * <code>repeated int32 content_type = 4;</code>\n       */\n      public Builder setContentType(\n          int index, int value) {\n        ensureContentTypeIsMutable();\n        contentType_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 content_type = 4;</code>\n       */\n      public Builder addContentType(int value) {\n        ensureContentTypeIsMutable();\n        contentType_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 content_type = 4;</code>\n       */\n      public Builder addAllContentType(\n          java.lang.Iterable<? extends java.lang.Integer> values) {\n        ensureContentTypeIsMutable();\n        super.addAll(values, contentType_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated int32 content_type = 4;</code>\n       */\n      public Builder clearContentType() {\n        contentType_ = java.util.Collections.emptyList();\n        bitField0_ = (bitField0_ & ~0x00000008);\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:LoadRemoteMessages)\n    }\n\n    static {\n      defaultInstance = new LoadRemoteMessages(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:LoadRemoteMessages)\n  }\n\n  public interface MultiCastMessageOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string from_user = 1;\n    /**\n     * <code>required string from_user = 1;</code>\n     */\n    boolean hasFromUser();\n    /**\n     * <code>required string from_user = 1;</code>\n     */\n    java.lang.String getFromUser();\n    /**\n     * <code>required string from_user = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getFromUserBytes();\n\n    // required .MessageContent content = 2;\n    /**\n     * <code>required .MessageContent content = 2;</code>\n     */\n    boolean hasContent();\n    /**\n     * <code>required .MessageContent content = 2;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContent getContent();\n    /**\n     * <code>required .MessageContent content = 2;</code>\n     */\n    cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getContentOrBuilder();\n\n    // repeated string to = 3;\n    /**\n     * <code>repeated string to = 3;</code>\n     */\n    java.util.List<java.lang.String>\n    getToList();\n    /**\n     * <code>repeated string to = 3;</code>\n     */\n    int getToCount();\n    /**\n     * <code>repeated string to = 3;</code>\n     */\n    java.lang.String getTo(int index);\n    /**\n     * <code>repeated string to = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getToBytes(int index);\n\n    // required int32 line = 4;\n    /**\n     * <code>required int32 line = 4;</code>\n     */\n    boolean hasLine();\n    /**\n     * <code>required int32 line = 4;</code>\n     */\n    int getLine();\n  }\n  /**\n   * Protobuf type {@code MultiCastMessage}\n   */\n  public static final class MultiCastMessage extends\n      com.google.protobuf.GeneratedMessage\n      implements MultiCastMessageOrBuilder {\n    // Use MultiCastMessage.newBuilder() to construct.\n    private MultiCastMessage(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private MultiCastMessage(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final MultiCastMessage defaultInstance;\n    public static MultiCastMessage getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public MultiCastMessage getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private MultiCastMessage(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              fromUser_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              cn.wildfirechat.proto.WFCMessage.MessageContent.Builder subBuilder = null;\n              if (((bitField0_ & 0x00000002) == 0x00000002)) {\n                subBuilder = content_.toBuilder();\n              }\n              content_ = input.readMessage(cn.wildfirechat.proto.WFCMessage.MessageContent.PARSER, extensionRegistry);\n              if (subBuilder != null) {\n                subBuilder.mergeFrom(content_);\n                content_ = subBuilder.buildPartial();\n              }\n              bitField0_ |= 0x00000002;\n              break;\n            }\n            case 26: {\n              if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n                to_ = new com.google.protobuf.LazyStringArrayList();\n                mutable_bitField0_ |= 0x00000004;\n              }\n              to_.add(input.readBytes());\n              break;\n            }\n            case 32: {\n              bitField0_ |= 0x00000004;\n              line_ = input.readInt32();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_ = new com.google.protobuf.UnmodifiableLazyStringList(to_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_MultiCastMessage_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_MultiCastMessage_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.MultiCastMessage.class, cn.wildfirechat.proto.WFCMessage.MultiCastMessage.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<MultiCastMessage> PARSER =\n        new com.google.protobuf.AbstractParser<MultiCastMessage>() {\n      public MultiCastMessage parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new MultiCastMessage(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<MultiCastMessage> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string from_user = 1;\n    public static final int FROM_USER_FIELD_NUMBER = 1;\n    private java.lang.Object fromUser_;\n    /**\n     * <code>required string from_user = 1;</code>\n     */\n    public boolean hasFromUser() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string from_user = 1;</code>\n     */\n    public java.lang.String getFromUser() {\n      java.lang.Object ref = fromUser_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          fromUser_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string from_user = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getFromUserBytes() {\n      java.lang.Object ref = fromUser_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        fromUser_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required .MessageContent content = 2;\n    public static final int CONTENT_FIELD_NUMBER = 2;\n    private cn.wildfirechat.proto.WFCMessage.MessageContent content_;\n    /**\n     * <code>required .MessageContent content = 2;</code>\n     */\n    public boolean hasContent() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required .MessageContent content = 2;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContent getContent() {\n      return content_;\n    }\n    /**\n     * <code>required .MessageContent content = 2;</code>\n     */\n    public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getContentOrBuilder() {\n      return content_;\n    }\n\n    // repeated string to = 3;\n    public static final int TO_FIELD_NUMBER = 3;\n    private com.google.protobuf.LazyStringList to_;\n    /**\n     * <code>repeated string to = 3;</code>\n     */\n    public java.util.List<java.lang.String>\n        getToList() {\n      return to_;\n    }\n    /**\n     * <code>repeated string to = 3;</code>\n     */\n    public int getToCount() {\n      return to_.size();\n    }\n    /**\n     * <code>repeated string to = 3;</code>\n     */\n    public java.lang.String getTo(int index) {\n      return to_.get(index);\n    }\n    /**\n     * <code>repeated string to = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getToBytes(int index) {\n      return to_.getByteString(index);\n    }\n\n    // required int32 line = 4;\n    public static final int LINE_FIELD_NUMBER = 4;\n    private int line_;\n    /**\n     * <code>required int32 line = 4;</code>\n     */\n    public boolean hasLine() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required int32 line = 4;</code>\n     */\n    public int getLine() {\n      return line_;\n    }\n\n    private void initFields() {\n      fromUser_ = \"\";\n      content_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      to_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      line_ = 0;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasFromUser()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasContent()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasLine()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!getContent().isInitialized()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getFromUserBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeMessage(2, content_);\n      }\n      for (int i = 0; i < to_.size(); i++) {\n        output.writeBytes(3, to_.getByteString(i));\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt32(4, line_);\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getFromUserBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeMessageSize(2, content_);\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < to_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeBytesSizeNoTag(to_.getByteString(i));\n        }\n        size += dataSize;\n        size += 1 * getToList().size();\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(4, line_);\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.MultiCastMessage parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MultiCastMessage parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MultiCastMessage parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MultiCastMessage parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MultiCastMessage parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MultiCastMessage parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MultiCastMessage parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MultiCastMessage parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MultiCastMessage parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.MultiCastMessage parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.MultiCastMessage prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code MultiCastMessage}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.MultiCastMessageOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_MultiCastMessage_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_MultiCastMessage_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.MultiCastMessage.class, cn.wildfirechat.proto.WFCMessage.MultiCastMessage.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.MultiCastMessage.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n          getContentFieldBuilder();\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        fromUser_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        if (contentBuilder_ == null) {\n          content_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n        } else {\n          contentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000002);\n        to_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        line_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000008);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_MultiCastMessage_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.MultiCastMessage getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.MultiCastMessage.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.MultiCastMessage build() {\n        cn.wildfirechat.proto.WFCMessage.MultiCastMessage result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.MultiCastMessage buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.MultiCastMessage result = new cn.wildfirechat.proto.WFCMessage.MultiCastMessage(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.fromUser_ = fromUser_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        if (contentBuilder_ == null) {\n          result.content_ = content_;\n        } else {\n          result.content_ = contentBuilder_.build();\n        }\n        if (((bitField0_ & 0x00000004) == 0x00000004)) {\n          to_ = new com.google.protobuf.UnmodifiableLazyStringList(\n              to_);\n          bitField0_ = (bitField0_ & ~0x00000004);\n        }\n        result.to_ = to_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.line_ = line_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.MultiCastMessage) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.MultiCastMessage)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.MultiCastMessage other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.MultiCastMessage.getDefaultInstance()) return this;\n        if (other.hasFromUser()) {\n          bitField0_ |= 0x00000001;\n          fromUser_ = other.fromUser_;\n          onChanged();\n        }\n        if (other.hasContent()) {\n          mergeContent(other.getContent());\n        }\n        if (!other.to_.isEmpty()) {\n          if (to_.isEmpty()) {\n            to_ = other.to_;\n            bitField0_ = (bitField0_ & ~0x00000004);\n          } else {\n            ensureToIsMutable();\n            to_.addAll(other.to_);\n          }\n          onChanged();\n        }\n        if (other.hasLine()) {\n          setLine(other.getLine());\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasFromUser()) {\n          \n          return false;\n        }\n        if (!hasContent()) {\n          \n          return false;\n        }\n        if (!hasLine()) {\n          \n          return false;\n        }\n        if (!getContent().isInitialized()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.MultiCastMessage parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.MultiCastMessage) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string from_user = 1;\n      private java.lang.Object fromUser_ = \"\";\n      /**\n       * <code>required string from_user = 1;</code>\n       */\n      public boolean hasFromUser() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string from_user = 1;</code>\n       */\n      public java.lang.String getFromUser() {\n        java.lang.Object ref = fromUser_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          fromUser_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string from_user = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getFromUserBytes() {\n        java.lang.Object ref = fromUser_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          fromUser_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string from_user = 1;</code>\n       */\n      public Builder setFromUser(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        fromUser_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string from_user = 1;</code>\n       */\n      public Builder clearFromUser() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        fromUser_ = getDefaultInstance().getFromUser();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string from_user = 1;</code>\n       */\n      public Builder setFromUserBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        fromUser_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required .MessageContent content = 2;\n      private cn.wildfirechat.proto.WFCMessage.MessageContent content_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> contentBuilder_;\n      /**\n       * <code>required .MessageContent content = 2;</code>\n       */\n      public boolean hasContent() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required .MessageContent content = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent getContent() {\n        if (contentBuilder_ == null) {\n          return content_;\n        } else {\n          return contentBuilder_.getMessage();\n        }\n      }\n      /**\n       * <code>required .MessageContent content = 2;</code>\n       */\n      public Builder setContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (contentBuilder_ == null) {\n          if (value == null) {\n            throw new NullPointerException();\n          }\n          content_ = value;\n          onChanged();\n        } else {\n          contentBuilder_.setMessage(value);\n        }\n        bitField0_ |= 0x00000002;\n        return this;\n      }\n      /**\n       * <code>required .MessageContent content = 2;</code>\n       */\n      public Builder setContent(\n          cn.wildfirechat.proto.WFCMessage.MessageContent.Builder builderForValue) {\n        if (contentBuilder_ == null) {\n          content_ = builderForValue.build();\n          onChanged();\n        } else {\n          contentBuilder_.setMessage(builderForValue.build());\n        }\n        bitField0_ |= 0x00000002;\n        return this;\n      }\n      /**\n       * <code>required .MessageContent content = 2;</code>\n       */\n      public Builder mergeContent(cn.wildfirechat.proto.WFCMessage.MessageContent value) {\n        if (contentBuilder_ == null) {\n          if (((bitField0_ & 0x00000002) == 0x00000002) &&\n              content_ != cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance()) {\n            content_ =\n              cn.wildfirechat.proto.WFCMessage.MessageContent.newBuilder(content_).mergeFrom(value).buildPartial();\n          } else {\n            content_ = value;\n          }\n          onChanged();\n        } else {\n          contentBuilder_.mergeFrom(value);\n        }\n        bitField0_ |= 0x00000002;\n        return this;\n      }\n      /**\n       * <code>required .MessageContent content = 2;</code>\n       */\n      public Builder clearContent() {\n        if (contentBuilder_ == null) {\n          content_ = cn.wildfirechat.proto.WFCMessage.MessageContent.getDefaultInstance();\n          onChanged();\n        } else {\n          contentBuilder_.clear();\n        }\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n      /**\n       * <code>required .MessageContent content = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContent.Builder getContentBuilder() {\n        bitField0_ |= 0x00000002;\n        onChanged();\n        return getContentFieldBuilder().getBuilder();\n      }\n      /**\n       * <code>required .MessageContent content = 2;</code>\n       */\n      public cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder getContentOrBuilder() {\n        if (contentBuilder_ != null) {\n          return contentBuilder_.getMessageOrBuilder();\n        } else {\n          return content_;\n        }\n      }\n      /**\n       * <code>required .MessageContent content = 2;</code>\n       */\n      private com.google.protobuf.SingleFieldBuilder<\n          cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder> \n          getContentFieldBuilder() {\n        if (contentBuilder_ == null) {\n          contentBuilder_ = new com.google.protobuf.SingleFieldBuilder<\n              cn.wildfirechat.proto.WFCMessage.MessageContent, cn.wildfirechat.proto.WFCMessage.MessageContent.Builder, cn.wildfirechat.proto.WFCMessage.MessageContentOrBuilder>(\n                  content_,\n                  getParentForChildren(),\n                  isClean());\n          content_ = null;\n        }\n        return contentBuilder_;\n      }\n\n      // repeated string to = 3;\n      private com.google.protobuf.LazyStringList to_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      private void ensureToIsMutable() {\n        if (!((bitField0_ & 0x00000004) == 0x00000004)) {\n          to_ = new com.google.protobuf.LazyStringArrayList(to_);\n          bitField0_ |= 0x00000004;\n         }\n      }\n      /**\n       * <code>repeated string to = 3;</code>\n       */\n      public java.util.List<java.lang.String>\n          getToList() {\n        return java.util.Collections.unmodifiableList(to_);\n      }\n      /**\n       * <code>repeated string to = 3;</code>\n       */\n      public int getToCount() {\n        return to_.size();\n      }\n      /**\n       * <code>repeated string to = 3;</code>\n       */\n      public java.lang.String getTo(int index) {\n        return to_.get(index);\n      }\n      /**\n       * <code>repeated string to = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getToBytes(int index) {\n        return to_.getByteString(index);\n      }\n      /**\n       * <code>repeated string to = 3;</code>\n       */\n      public Builder setTo(\n          int index, java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureToIsMutable();\n        to_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string to = 3;</code>\n       */\n      public Builder addTo(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureToIsMutable();\n        to_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string to = 3;</code>\n       */\n      public Builder addAllTo(\n          java.lang.Iterable<java.lang.String> values) {\n        ensureToIsMutable();\n        super.addAll(values, to_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string to = 3;</code>\n       */\n      public Builder clearTo() {\n        to_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string to = 3;</code>\n       */\n      public Builder addToBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureToIsMutable();\n        to_.add(value);\n        onChanged();\n        return this;\n      }\n\n      // required int32 line = 4;\n      private int line_ ;\n      /**\n       * <code>required int32 line = 4;</code>\n       */\n      public boolean hasLine() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>required int32 line = 4;</code>\n       */\n      public int getLine() {\n        return line_;\n      }\n      /**\n       * <code>required int32 line = 4;</code>\n       */\n      public Builder setLine(int value) {\n        bitField0_ |= 0x00000008;\n        line_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 line = 4;</code>\n       */\n      public Builder clearLine() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        line_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:MultiCastMessage)\n    }\n\n    static {\n      defaultInstance = new MultiCastMessage(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:MultiCastMessage)\n  }\n\n  public interface RecallMultiCastMessageRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required int64 message_id = 1;\n    /**\n     * <code>required int64 message_id = 1;</code>\n     */\n    boolean hasMessageId();\n    /**\n     * <code>required int64 message_id = 1;</code>\n     */\n    long getMessageId();\n\n    // repeated string receiver = 2;\n    /**\n     * <code>repeated string receiver = 2;</code>\n     */\n    java.util.List<java.lang.String>\n    getReceiverList();\n    /**\n     * <code>repeated string receiver = 2;</code>\n     */\n    int getReceiverCount();\n    /**\n     * <code>repeated string receiver = 2;</code>\n     */\n    java.lang.String getReceiver(int index);\n    /**\n     * <code>repeated string receiver = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getReceiverBytes(int index);\n  }\n  /**\n   * Protobuf type {@code RecallMultiCastMessageRequest}\n   */\n  public static final class RecallMultiCastMessageRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements RecallMultiCastMessageRequestOrBuilder {\n    // Use RecallMultiCastMessageRequest.newBuilder() to construct.\n    private RecallMultiCastMessageRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private RecallMultiCastMessageRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final RecallMultiCastMessageRequest defaultInstance;\n    public static RecallMultiCastMessageRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public RecallMultiCastMessageRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private RecallMultiCastMessageRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 8: {\n              bitField0_ |= 0x00000001;\n              messageId_ = input.readInt64();\n              break;\n            }\n            case 18: {\n              if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n                receiver_ = new com.google.protobuf.LazyStringArrayList();\n                mutable_bitField0_ |= 0x00000002;\n              }\n              receiver_.add(input.readBytes());\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) {\n          receiver_ = new com.google.protobuf.UnmodifiableLazyStringList(receiver_);\n        }\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_RecallMultiCastMessageRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_RecallMultiCastMessageRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest.class, cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<RecallMultiCastMessageRequest> PARSER =\n        new com.google.protobuf.AbstractParser<RecallMultiCastMessageRequest>() {\n      public RecallMultiCastMessageRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new RecallMultiCastMessageRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<RecallMultiCastMessageRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required int64 message_id = 1;\n    public static final int MESSAGE_ID_FIELD_NUMBER = 1;\n    private long messageId_;\n    /**\n     * <code>required int64 message_id = 1;</code>\n     */\n    public boolean hasMessageId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required int64 message_id = 1;</code>\n     */\n    public long getMessageId() {\n      return messageId_;\n    }\n\n    // repeated string receiver = 2;\n    public static final int RECEIVER_FIELD_NUMBER = 2;\n    private com.google.protobuf.LazyStringList receiver_;\n    /**\n     * <code>repeated string receiver = 2;</code>\n     */\n    public java.util.List<java.lang.String>\n        getReceiverList() {\n      return receiver_;\n    }\n    /**\n     * <code>repeated string receiver = 2;</code>\n     */\n    public int getReceiverCount() {\n      return receiver_.size();\n    }\n    /**\n     * <code>repeated string receiver = 2;</code>\n     */\n    public java.lang.String getReceiver(int index) {\n      return receiver_.get(index);\n    }\n    /**\n     * <code>repeated string receiver = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getReceiverBytes(int index) {\n      return receiver_.getByteString(index);\n    }\n\n    private void initFields() {\n      messageId_ = 0L;\n      receiver_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasMessageId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeInt64(1, messageId_);\n      }\n      for (int i = 0; i < receiver_.size(); i++) {\n        output.writeBytes(2, receiver_.getByteString(i));\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(1, messageId_);\n      }\n      {\n        int dataSize = 0;\n        for (int i = 0; i < receiver_.size(); i++) {\n          dataSize += com.google.protobuf.CodedOutputStream\n            .computeBytesSizeNoTag(receiver_.getByteString(i));\n        }\n        size += dataSize;\n        size += 1 * getReceiverList().size();\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code RecallMultiCastMessageRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_RecallMultiCastMessageRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_RecallMultiCastMessageRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest.class, cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        messageId_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000001);\n        receiver_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_RecallMultiCastMessageRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest build() {\n        cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest result = new cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.messageId_ = messageId_;\n        if (((bitField0_ & 0x00000002) == 0x00000002)) {\n          receiver_ = new com.google.protobuf.UnmodifiableLazyStringList(\n              receiver_);\n          bitField0_ = (bitField0_ & ~0x00000002);\n        }\n        result.receiver_ = receiver_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest.getDefaultInstance()) return this;\n        if (other.hasMessageId()) {\n          setMessageId(other.getMessageId());\n        }\n        if (!other.receiver_.isEmpty()) {\n          if (receiver_.isEmpty()) {\n            receiver_ = other.receiver_;\n            bitField0_ = (bitField0_ & ~0x00000002);\n          } else {\n            ensureReceiverIsMutable();\n            receiver_.addAll(other.receiver_);\n          }\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasMessageId()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.RecallMultiCastMessageRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required int64 message_id = 1;\n      private long messageId_ ;\n      /**\n       * <code>required int64 message_id = 1;</code>\n       */\n      public boolean hasMessageId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required int64 message_id = 1;</code>\n       */\n      public long getMessageId() {\n        return messageId_;\n      }\n      /**\n       * <code>required int64 message_id = 1;</code>\n       */\n      public Builder setMessageId(long value) {\n        bitField0_ |= 0x00000001;\n        messageId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 message_id = 1;</code>\n       */\n      public Builder clearMessageId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        messageId_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // repeated string receiver = 2;\n      private com.google.protobuf.LazyStringList receiver_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n      private void ensureReceiverIsMutable() {\n        if (!((bitField0_ & 0x00000002) == 0x00000002)) {\n          receiver_ = new com.google.protobuf.LazyStringArrayList(receiver_);\n          bitField0_ |= 0x00000002;\n         }\n      }\n      /**\n       * <code>repeated string receiver = 2;</code>\n       */\n      public java.util.List<java.lang.String>\n          getReceiverList() {\n        return java.util.Collections.unmodifiableList(receiver_);\n      }\n      /**\n       * <code>repeated string receiver = 2;</code>\n       */\n      public int getReceiverCount() {\n        return receiver_.size();\n      }\n      /**\n       * <code>repeated string receiver = 2;</code>\n       */\n      public java.lang.String getReceiver(int index) {\n        return receiver_.get(index);\n      }\n      /**\n       * <code>repeated string receiver = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getReceiverBytes(int index) {\n        return receiver_.getByteString(index);\n      }\n      /**\n       * <code>repeated string receiver = 2;</code>\n       */\n      public Builder setReceiver(\n          int index, java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureReceiverIsMutable();\n        receiver_.set(index, value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string receiver = 2;</code>\n       */\n      public Builder addReceiver(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureReceiverIsMutable();\n        receiver_.add(value);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string receiver = 2;</code>\n       */\n      public Builder addAllReceiver(\n          java.lang.Iterable<java.lang.String> values) {\n        ensureReceiverIsMutable();\n        super.addAll(values, receiver_);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string receiver = 2;</code>\n       */\n      public Builder clearReceiver() {\n        receiver_ = com.google.protobuf.LazyStringArrayList.EMPTY;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>repeated string receiver = 2;</code>\n       */\n      public Builder addReceiverBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  ensureReceiverIsMutable();\n        receiver_.add(value);\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:RecallMultiCastMessageRequest)\n    }\n\n    static {\n      defaultInstance = new RecallMultiCastMessageRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:RecallMultiCastMessageRequest)\n  }\n\n  public interface AuthCodeRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string target_id = 1;\n    /**\n     * <code>required string target_id = 1;</code>\n     */\n    boolean hasTargetId();\n    /**\n     * <code>required string target_id = 1;</code>\n     */\n    java.lang.String getTargetId();\n    /**\n     * <code>required string target_id = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getTargetIdBytes();\n\n    // required int32 type = 2;\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    boolean hasType();\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    int getType();\n\n    // required string host = 3;\n    /**\n     * <code>required string host = 3;</code>\n     */\n    boolean hasHost();\n    /**\n     * <code>required string host = 3;</code>\n     */\n    java.lang.String getHost();\n    /**\n     * <code>required string host = 3;</code>\n     */\n    com.google.protobuf.ByteString\n        getHostBytes();\n  }\n  /**\n   * Protobuf type {@code AuthCodeRequest}\n   */\n  public static final class AuthCodeRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements AuthCodeRequestOrBuilder {\n    // Use AuthCodeRequest.newBuilder() to construct.\n    private AuthCodeRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private AuthCodeRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final AuthCodeRequest defaultInstance;\n    public static AuthCodeRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public AuthCodeRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private AuthCodeRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              targetId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              type_ = input.readInt32();\n              break;\n            }\n            case 26: {\n              bitField0_ |= 0x00000004;\n              host_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_AuthCodeRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_AuthCodeRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.AuthCodeRequest.class, cn.wildfirechat.proto.WFCMessage.AuthCodeRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<AuthCodeRequest> PARSER =\n        new com.google.protobuf.AbstractParser<AuthCodeRequest>() {\n      public AuthCodeRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new AuthCodeRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<AuthCodeRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string target_id = 1;\n    public static final int TARGET_ID_FIELD_NUMBER = 1;\n    private java.lang.Object targetId_;\n    /**\n     * <code>required string target_id = 1;</code>\n     */\n    public boolean hasTargetId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string target_id = 1;</code>\n     */\n    public java.lang.String getTargetId() {\n      java.lang.Object ref = targetId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          targetId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string target_id = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getTargetIdBytes() {\n      java.lang.Object ref = targetId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        targetId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 type = 2;\n    public static final int TYPE_FIELD_NUMBER = 2;\n    private int type_;\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    public boolean hasType() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 type = 2;</code>\n     */\n    public int getType() {\n      return type_;\n    }\n\n    // required string host = 3;\n    public static final int HOST_FIELD_NUMBER = 3;\n    private java.lang.Object host_;\n    /**\n     * <code>required string host = 3;</code>\n     */\n    public boolean hasHost() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required string host = 3;</code>\n     */\n    public java.lang.String getHost() {\n      java.lang.Object ref = host_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          host_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string host = 3;</code>\n     */\n    public com.google.protobuf.ByteString\n        getHostBytes() {\n      java.lang.Object ref = host_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        host_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      targetId_ = \"\";\n      type_ = 0;\n      host_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasTargetId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasHost()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getTargetIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, type_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeBytes(3, getHostBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getTargetIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, type_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(3, getHostBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.AuthCodeRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AuthCodeRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AuthCodeRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AuthCodeRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AuthCodeRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AuthCodeRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AuthCodeRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AuthCodeRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AuthCodeRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.AuthCodeRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.AuthCodeRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code AuthCodeRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.AuthCodeRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_AuthCodeRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_AuthCodeRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.AuthCodeRequest.class, cn.wildfirechat.proto.WFCMessage.AuthCodeRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.AuthCodeRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        targetId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        type_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        host_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000004);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_AuthCodeRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.AuthCodeRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.AuthCodeRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.AuthCodeRequest build() {\n        cn.wildfirechat.proto.WFCMessage.AuthCodeRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.AuthCodeRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.AuthCodeRequest result = new cn.wildfirechat.proto.WFCMessage.AuthCodeRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.targetId_ = targetId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.type_ = type_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.host_ = host_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.AuthCodeRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.AuthCodeRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.AuthCodeRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.AuthCodeRequest.getDefaultInstance()) return this;\n        if (other.hasTargetId()) {\n          bitField0_ |= 0x00000001;\n          targetId_ = other.targetId_;\n          onChanged();\n        }\n        if (other.hasType()) {\n          setType(other.getType());\n        }\n        if (other.hasHost()) {\n          bitField0_ |= 0x00000004;\n          host_ = other.host_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasTargetId()) {\n          \n          return false;\n        }\n        if (!hasType()) {\n          \n          return false;\n        }\n        if (!hasHost()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.AuthCodeRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.AuthCodeRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string target_id = 1;\n      private java.lang.Object targetId_ = \"\";\n      /**\n       * <code>required string target_id = 1;</code>\n       */\n      public boolean hasTargetId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string target_id = 1;</code>\n       */\n      public java.lang.String getTargetId() {\n        java.lang.Object ref = targetId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          targetId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string target_id = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getTargetIdBytes() {\n        java.lang.Object ref = targetId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          targetId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string target_id = 1;</code>\n       */\n      public Builder setTargetId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        targetId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string target_id = 1;</code>\n       */\n      public Builder clearTargetId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        targetId_ = getDefaultInstance().getTargetId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string target_id = 1;</code>\n       */\n      public Builder setTargetIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        targetId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 type = 2;\n      private int type_ ;\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public boolean hasType() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public int getType() {\n        return type_;\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public Builder setType(int value) {\n        bitField0_ |= 0x00000002;\n        type_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 type = 2;</code>\n       */\n      public Builder clearType() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        type_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required string host = 3;\n      private java.lang.Object host_ = \"\";\n      /**\n       * <code>required string host = 3;</code>\n       */\n      public boolean hasHost() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required string host = 3;</code>\n       */\n      public java.lang.String getHost() {\n        java.lang.Object ref = host_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          host_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string host = 3;</code>\n       */\n      public com.google.protobuf.ByteString\n          getHostBytes() {\n        java.lang.Object ref = host_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          host_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string host = 3;</code>\n       */\n      public Builder setHost(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        host_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string host = 3;</code>\n       */\n      public Builder clearHost() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        host_ = getDefaultInstance().getHost();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string host = 3;</code>\n       */\n      public Builder setHostBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000004;\n        host_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:AuthCodeRequest)\n    }\n\n    static {\n      defaultInstance = new AuthCodeRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:AuthCodeRequest)\n  }\n\n  public interface ApplicationConfigRequestOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string appId = 1;\n    /**\n     * <code>required string appId = 1;</code>\n     */\n    boolean hasAppId();\n    /**\n     * <code>required string appId = 1;</code>\n     */\n    java.lang.String getAppId();\n    /**\n     * <code>required string appId = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getAppIdBytes();\n\n    // required int32 appType = 2;\n    /**\n     * <code>required int32 appType = 2;</code>\n     */\n    boolean hasAppType();\n    /**\n     * <code>required int32 appType = 2;</code>\n     */\n    int getAppType();\n\n    // required int64 timestamp = 3;\n    /**\n     * <code>required int64 timestamp = 3;</code>\n     */\n    boolean hasTimestamp();\n    /**\n     * <code>required int64 timestamp = 3;</code>\n     */\n    long getTimestamp();\n\n    // required string nonce = 4;\n    /**\n     * <code>required string nonce = 4;</code>\n     */\n    boolean hasNonce();\n    /**\n     * <code>required string nonce = 4;</code>\n     */\n    java.lang.String getNonce();\n    /**\n     * <code>required string nonce = 4;</code>\n     */\n    com.google.protobuf.ByteString\n        getNonceBytes();\n\n    // required string signature = 5;\n    /**\n     * <code>required string signature = 5;</code>\n     */\n    boolean hasSignature();\n    /**\n     * <code>required string signature = 5;</code>\n     */\n    java.lang.String getSignature();\n    /**\n     * <code>required string signature = 5;</code>\n     */\n    com.google.protobuf.ByteString\n        getSignatureBytes();\n  }\n  /**\n   * Protobuf type {@code ApplicationConfigRequest}\n   */\n  public static final class ApplicationConfigRequest extends\n      com.google.protobuf.GeneratedMessage\n      implements ApplicationConfigRequestOrBuilder {\n    // Use ApplicationConfigRequest.newBuilder() to construct.\n    private ApplicationConfigRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private ApplicationConfigRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final ApplicationConfigRequest defaultInstance;\n    public static ApplicationConfigRequest getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public ApplicationConfigRequest getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private ApplicationConfigRequest(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              appId_ = input.readBytes();\n              break;\n            }\n            case 16: {\n              bitField0_ |= 0x00000002;\n              appType_ = input.readInt32();\n              break;\n            }\n            case 24: {\n              bitField0_ |= 0x00000004;\n              timestamp_ = input.readInt64();\n              break;\n            }\n            case 34: {\n              bitField0_ |= 0x00000008;\n              nonce_ = input.readBytes();\n              break;\n            }\n            case 42: {\n              bitField0_ |= 0x00000010;\n              signature_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ApplicationConfigRequest_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_ApplicationConfigRequest_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest.class, cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<ApplicationConfigRequest> PARSER =\n        new com.google.protobuf.AbstractParser<ApplicationConfigRequest>() {\n      public ApplicationConfigRequest parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new ApplicationConfigRequest(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<ApplicationConfigRequest> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string appId = 1;\n    public static final int APPID_FIELD_NUMBER = 1;\n    private java.lang.Object appId_;\n    /**\n     * <code>required string appId = 1;</code>\n     */\n    public boolean hasAppId() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string appId = 1;</code>\n     */\n    public java.lang.String getAppId() {\n      java.lang.Object ref = appId_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          appId_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string appId = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getAppIdBytes() {\n      java.lang.Object ref = appId_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        appId_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required int32 appType = 2;\n    public static final int APPTYPE_FIELD_NUMBER = 2;\n    private int appType_;\n    /**\n     * <code>required int32 appType = 2;</code>\n     */\n    public boolean hasAppType() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>required int32 appType = 2;</code>\n     */\n    public int getAppType() {\n      return appType_;\n    }\n\n    // required int64 timestamp = 3;\n    public static final int TIMESTAMP_FIELD_NUMBER = 3;\n    private long timestamp_;\n    /**\n     * <code>required int64 timestamp = 3;</code>\n     */\n    public boolean hasTimestamp() {\n      return ((bitField0_ & 0x00000004) == 0x00000004);\n    }\n    /**\n     * <code>required int64 timestamp = 3;</code>\n     */\n    public long getTimestamp() {\n      return timestamp_;\n    }\n\n    // required string nonce = 4;\n    public static final int NONCE_FIELD_NUMBER = 4;\n    private java.lang.Object nonce_;\n    /**\n     * <code>required string nonce = 4;</code>\n     */\n    public boolean hasNonce() {\n      return ((bitField0_ & 0x00000008) == 0x00000008);\n    }\n    /**\n     * <code>required string nonce = 4;</code>\n     */\n    public java.lang.String getNonce() {\n      java.lang.Object ref = nonce_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          nonce_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string nonce = 4;</code>\n     */\n    public com.google.protobuf.ByteString\n        getNonceBytes() {\n      java.lang.Object ref = nonce_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        nonce_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // required string signature = 5;\n    public static final int SIGNATURE_FIELD_NUMBER = 5;\n    private java.lang.Object signature_;\n    /**\n     * <code>required string signature = 5;</code>\n     */\n    public boolean hasSignature() {\n      return ((bitField0_ & 0x00000010) == 0x00000010);\n    }\n    /**\n     * <code>required string signature = 5;</code>\n     */\n    public java.lang.String getSignature() {\n      java.lang.Object ref = signature_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          signature_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string signature = 5;</code>\n     */\n    public com.google.protobuf.ByteString\n        getSignatureBytes() {\n      java.lang.Object ref = signature_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        signature_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      appId_ = \"\";\n      appType_ = 0;\n      timestamp_ = 0L;\n      nonce_ = \"\";\n      signature_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasAppId()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasAppType()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasTimestamp()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasNonce()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      if (!hasSignature()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getAppIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeInt32(2, appType_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        output.writeInt64(3, timestamp_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        output.writeBytes(4, getNonceBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        output.writeBytes(5, getSignatureBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getAppIdBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt32Size(2, appType_);\n      }\n      if (((bitField0_ & 0x00000004) == 0x00000004)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeInt64Size(3, timestamp_);\n      }\n      if (((bitField0_ & 0x00000008) == 0x00000008)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(4, getNonceBytes());\n      }\n      if (((bitField0_ & 0x00000010) == 0x00000010)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(5, getSignatureBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code ApplicationConfigRequest}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequestOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ApplicationConfigRequest_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ApplicationConfigRequest_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest.class, cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        appId_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        appType_ = 0;\n        bitField0_ = (bitField0_ & ~0x00000002);\n        timestamp_ = 0L;\n        bitField0_ = (bitField0_ & ~0x00000004);\n        nonce_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000008);\n        signature_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000010);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_ApplicationConfigRequest_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest build() {\n        cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest result = new cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.appId_ = appId_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.appType_ = appType_;\n        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {\n          to_bitField0_ |= 0x00000004;\n        }\n        result.timestamp_ = timestamp_;\n        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {\n          to_bitField0_ |= 0x00000008;\n        }\n        result.nonce_ = nonce_;\n        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {\n          to_bitField0_ |= 0x00000010;\n        }\n        result.signature_ = signature_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest.getDefaultInstance()) return this;\n        if (other.hasAppId()) {\n          bitField0_ |= 0x00000001;\n          appId_ = other.appId_;\n          onChanged();\n        }\n        if (other.hasAppType()) {\n          setAppType(other.getAppType());\n        }\n        if (other.hasTimestamp()) {\n          setTimestamp(other.getTimestamp());\n        }\n        if (other.hasNonce()) {\n          bitField0_ |= 0x00000008;\n          nonce_ = other.nonce_;\n          onChanged();\n        }\n        if (other.hasSignature()) {\n          bitField0_ |= 0x00000010;\n          signature_ = other.signature_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasAppId()) {\n          \n          return false;\n        }\n        if (!hasAppType()) {\n          \n          return false;\n        }\n        if (!hasTimestamp()) {\n          \n          return false;\n        }\n        if (!hasNonce()) {\n          \n          return false;\n        }\n        if (!hasSignature()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.ApplicationConfigRequest) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string appId = 1;\n      private java.lang.Object appId_ = \"\";\n      /**\n       * <code>required string appId = 1;</code>\n       */\n      public boolean hasAppId() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string appId = 1;</code>\n       */\n      public java.lang.String getAppId() {\n        java.lang.Object ref = appId_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          appId_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string appId = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getAppIdBytes() {\n        java.lang.Object ref = appId_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          appId_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string appId = 1;</code>\n       */\n      public Builder setAppId(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        appId_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string appId = 1;</code>\n       */\n      public Builder clearAppId() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        appId_ = getDefaultInstance().getAppId();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string appId = 1;</code>\n       */\n      public Builder setAppIdBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        appId_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required int32 appType = 2;\n      private int appType_ ;\n      /**\n       * <code>required int32 appType = 2;</code>\n       */\n      public boolean hasAppType() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>required int32 appType = 2;</code>\n       */\n      public int getAppType() {\n        return appType_;\n      }\n      /**\n       * <code>required int32 appType = 2;</code>\n       */\n      public Builder setAppType(int value) {\n        bitField0_ |= 0x00000002;\n        appType_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int32 appType = 2;</code>\n       */\n      public Builder clearAppType() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        appType_ = 0;\n        onChanged();\n        return this;\n      }\n\n      // required int64 timestamp = 3;\n      private long timestamp_ ;\n      /**\n       * <code>required int64 timestamp = 3;</code>\n       */\n      public boolean hasTimestamp() {\n        return ((bitField0_ & 0x00000004) == 0x00000004);\n      }\n      /**\n       * <code>required int64 timestamp = 3;</code>\n       */\n      public long getTimestamp() {\n        return timestamp_;\n      }\n      /**\n       * <code>required int64 timestamp = 3;</code>\n       */\n      public Builder setTimestamp(long value) {\n        bitField0_ |= 0x00000004;\n        timestamp_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required int64 timestamp = 3;</code>\n       */\n      public Builder clearTimestamp() {\n        bitField0_ = (bitField0_ & ~0x00000004);\n        timestamp_ = 0L;\n        onChanged();\n        return this;\n      }\n\n      // required string nonce = 4;\n      private java.lang.Object nonce_ = \"\";\n      /**\n       * <code>required string nonce = 4;</code>\n       */\n      public boolean hasNonce() {\n        return ((bitField0_ & 0x00000008) == 0x00000008);\n      }\n      /**\n       * <code>required string nonce = 4;</code>\n       */\n      public java.lang.String getNonce() {\n        java.lang.Object ref = nonce_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          nonce_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string nonce = 4;</code>\n       */\n      public com.google.protobuf.ByteString\n          getNonceBytes() {\n        java.lang.Object ref = nonce_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          nonce_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string nonce = 4;</code>\n       */\n      public Builder setNonce(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        nonce_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string nonce = 4;</code>\n       */\n      public Builder clearNonce() {\n        bitField0_ = (bitField0_ & ~0x00000008);\n        nonce_ = getDefaultInstance().getNonce();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string nonce = 4;</code>\n       */\n      public Builder setNonceBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000008;\n        nonce_ = value;\n        onChanged();\n        return this;\n      }\n\n      // required string signature = 5;\n      private java.lang.Object signature_ = \"\";\n      /**\n       * <code>required string signature = 5;</code>\n       */\n      public boolean hasSignature() {\n        return ((bitField0_ & 0x00000010) == 0x00000010);\n      }\n      /**\n       * <code>required string signature = 5;</code>\n       */\n      public java.lang.String getSignature() {\n        java.lang.Object ref = signature_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          signature_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string signature = 5;</code>\n       */\n      public com.google.protobuf.ByteString\n          getSignatureBytes() {\n        java.lang.Object ref = signature_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          signature_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string signature = 5;</code>\n       */\n      public Builder setSignature(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        signature_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string signature = 5;</code>\n       */\n      public Builder clearSignature() {\n        bitField0_ = (bitField0_ & ~0x00000010);\n        signature_ = getDefaultInstance().getSignature();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string signature = 5;</code>\n       */\n      public Builder setSignatureBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000010;\n        signature_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:ApplicationConfigRequest)\n    }\n\n    static {\n      defaultInstance = new ApplicationConfigRequest(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:ApplicationConfigRequest)\n  }\n\n  public interface StringPairOrBuilder\n      extends com.google.protobuf.MessageOrBuilder {\n\n    // required string key = 1;\n    /**\n     * <code>required string key = 1;</code>\n     */\n    boolean hasKey();\n    /**\n     * <code>required string key = 1;</code>\n     */\n    java.lang.String getKey();\n    /**\n     * <code>required string key = 1;</code>\n     */\n    com.google.protobuf.ByteString\n        getKeyBytes();\n\n    // optional string value = 2;\n    /**\n     * <code>optional string value = 2;</code>\n     */\n    boolean hasValue();\n    /**\n     * <code>optional string value = 2;</code>\n     */\n    java.lang.String getValue();\n    /**\n     * <code>optional string value = 2;</code>\n     */\n    com.google.protobuf.ByteString\n        getValueBytes();\n  }\n  /**\n   * Protobuf type {@code StringPair}\n   */\n  public static final class StringPair extends\n      com.google.protobuf.GeneratedMessage\n      implements StringPairOrBuilder {\n    // Use StringPair.newBuilder() to construct.\n    private StringPair(com.google.protobuf.GeneratedMessage.Builder<?> builder) {\n      super(builder);\n      this.unknownFields = builder.getUnknownFields();\n    }\n    private StringPair(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }\n\n    private static final StringPair defaultInstance;\n    public static StringPair getDefaultInstance() {\n      return defaultInstance;\n    }\n\n    public StringPair getDefaultInstanceForType() {\n      return defaultInstance;\n    }\n\n    private final com.google.protobuf.UnknownFieldSet unknownFields;\n    @java.lang.Override\n    public final com.google.protobuf.UnknownFieldSet\n        getUnknownFields() {\n      return this.unknownFields;\n    }\n    private StringPair(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      initFields();\n      int mutable_bitField0_ = 0;\n      com.google.protobuf.UnknownFieldSet.Builder unknownFields =\n          com.google.protobuf.UnknownFieldSet.newBuilder();\n      try {\n        boolean done = false;\n        while (!done) {\n          int tag = input.readTag();\n          switch (tag) {\n            case 0:\n              done = true;\n              break;\n            default: {\n              if (!parseUnknownField(input, unknownFields,\n                                     extensionRegistry, tag)) {\n                done = true;\n              }\n              break;\n            }\n            case 10: {\n              bitField0_ |= 0x00000001;\n              key_ = input.readBytes();\n              break;\n            }\n            case 18: {\n              bitField0_ |= 0x00000002;\n              value_ = input.readBytes();\n              break;\n            }\n          }\n        }\n      } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n        throw e.setUnfinishedMessage(this);\n      } catch (java.io.IOException e) {\n        throw new com.google.protobuf.InvalidProtocolBufferException(\n            e.getMessage()).setUnfinishedMessage(this);\n      } finally {\n        this.unknownFields = unknownFields.build();\n        makeExtensionsImmutable();\n      }\n    }\n    public static final com.google.protobuf.Descriptors.Descriptor\n        getDescriptor() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_StringPair_descriptor;\n    }\n\n    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n        internalGetFieldAccessorTable() {\n      return cn.wildfirechat.proto.WFCMessage.internal_static_StringPair_fieldAccessorTable\n          .ensureFieldAccessorsInitialized(\n              cn.wildfirechat.proto.WFCMessage.StringPair.class, cn.wildfirechat.proto.WFCMessage.StringPair.Builder.class);\n    }\n\n    public static com.google.protobuf.Parser<StringPair> PARSER =\n        new com.google.protobuf.AbstractParser<StringPair>() {\n      public StringPair parsePartialFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws com.google.protobuf.InvalidProtocolBufferException {\n        return new StringPair(input, extensionRegistry);\n      }\n    };\n\n    @java.lang.Override\n    public com.google.protobuf.Parser<StringPair> getParserForType() {\n      return PARSER;\n    }\n\n    private int bitField0_;\n    // required string key = 1;\n    public static final int KEY_FIELD_NUMBER = 1;\n    private java.lang.Object key_;\n    /**\n     * <code>required string key = 1;</code>\n     */\n    public boolean hasKey() {\n      return ((bitField0_ & 0x00000001) == 0x00000001);\n    }\n    /**\n     * <code>required string key = 1;</code>\n     */\n    public java.lang.String getKey() {\n      java.lang.Object ref = key_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          key_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>required string key = 1;</code>\n     */\n    public com.google.protobuf.ByteString\n        getKeyBytes() {\n      java.lang.Object ref = key_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        key_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    // optional string value = 2;\n    public static final int VALUE_FIELD_NUMBER = 2;\n    private java.lang.Object value_;\n    /**\n     * <code>optional string value = 2;</code>\n     */\n    public boolean hasValue() {\n      return ((bitField0_ & 0x00000002) == 0x00000002);\n    }\n    /**\n     * <code>optional string value = 2;</code>\n     */\n    public java.lang.String getValue() {\n      java.lang.Object ref = value_;\n      if (ref instanceof java.lang.String) {\n        return (java.lang.String) ref;\n      } else {\n        com.google.protobuf.ByteString bs = \n            (com.google.protobuf.ByteString) ref;\n        java.lang.String s = bs.toStringUtf8();\n        if (bs.isValidUtf8()) {\n          value_ = s;\n        }\n        return s;\n      }\n    }\n    /**\n     * <code>optional string value = 2;</code>\n     */\n    public com.google.protobuf.ByteString\n        getValueBytes() {\n      java.lang.Object ref = value_;\n      if (ref instanceof java.lang.String) {\n        com.google.protobuf.ByteString b = \n            com.google.protobuf.ByteString.copyFromUtf8(\n                (java.lang.String) ref);\n        value_ = b;\n        return b;\n      } else {\n        return (com.google.protobuf.ByteString) ref;\n      }\n    }\n\n    private void initFields() {\n      key_ = \"\";\n      value_ = \"\";\n    }\n    private byte memoizedIsInitialized = -1;\n    public final boolean isInitialized() {\n      byte isInitialized = memoizedIsInitialized;\n      if (isInitialized != -1) return isInitialized == 1;\n\n      if (!hasKey()) {\n        memoizedIsInitialized = 0;\n        return false;\n      }\n      memoizedIsInitialized = 1;\n      return true;\n    }\n\n    public void writeTo(com.google.protobuf.CodedOutputStream output)\n                        throws java.io.IOException {\n      getSerializedSize();\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        output.writeBytes(1, getKeyBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        output.writeBytes(2, getValueBytes());\n      }\n      getUnknownFields().writeTo(output);\n    }\n\n    private int memoizedSerializedSize = -1;\n    public int getSerializedSize() {\n      int size = memoizedSerializedSize;\n      if (size != -1) return size;\n\n      size = 0;\n      if (((bitField0_ & 0x00000001) == 0x00000001)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(1, getKeyBytes());\n      }\n      if (((bitField0_ & 0x00000002) == 0x00000002)) {\n        size += com.google.protobuf.CodedOutputStream\n          .computeBytesSize(2, getValueBytes());\n      }\n      size += getUnknownFields().getSerializedSize();\n      memoizedSerializedSize = size;\n      return size;\n    }\n\n    private static final long serialVersionUID = 0L;\n    @java.lang.Override\n    protected java.lang.Object writeReplace()\n        throws java.io.ObjectStreamException {\n      return super.writeReplace();\n    }\n\n    public static cn.wildfirechat.proto.WFCMessage.StringPair parseFrom(\n        com.google.protobuf.ByteString data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.StringPair parseFrom(\n        com.google.protobuf.ByteString data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.StringPair parseFrom(byte[] data)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.StringPair parseFrom(\n        byte[] data,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws com.google.protobuf.InvalidProtocolBufferException {\n      return PARSER.parseFrom(data, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.StringPair parseFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.StringPair parseFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.StringPair parseDelimitedFrom(java.io.InputStream input)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.StringPair parseDelimitedFrom(\n        java.io.InputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseDelimitedFrom(input, extensionRegistry);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.StringPair parseFrom(\n        com.google.protobuf.CodedInputStream input)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input);\n    }\n    public static cn.wildfirechat.proto.WFCMessage.StringPair parseFrom(\n        com.google.protobuf.CodedInputStream input,\n        com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n        throws java.io.IOException {\n      return PARSER.parseFrom(input, extensionRegistry);\n    }\n\n    public static Builder newBuilder() { return Builder.create(); }\n    public Builder newBuilderForType() { return newBuilder(); }\n    public static Builder newBuilder(cn.wildfirechat.proto.WFCMessage.StringPair prototype) {\n      return newBuilder().mergeFrom(prototype);\n    }\n    public Builder toBuilder() { return newBuilder(this); }\n\n    @java.lang.Override\n    protected Builder newBuilderForType(\n        com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n      Builder builder = new Builder(parent);\n      return builder;\n    }\n    /**\n     * Protobuf type {@code StringPair}\n     */\n    public static final class Builder extends\n        com.google.protobuf.GeneratedMessage.Builder<Builder>\n       implements cn.wildfirechat.proto.WFCMessage.StringPairOrBuilder {\n      public static final com.google.protobuf.Descriptors.Descriptor\n          getDescriptor() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_StringPair_descriptor;\n      }\n\n      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable\n          internalGetFieldAccessorTable() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_StringPair_fieldAccessorTable\n            .ensureFieldAccessorsInitialized(\n                cn.wildfirechat.proto.WFCMessage.StringPair.class, cn.wildfirechat.proto.WFCMessage.StringPair.Builder.class);\n      }\n\n      // Construct using cn.wildfirechat.proto.WFCMessage.StringPair.newBuilder()\n      private Builder() {\n        maybeForceBuilderInitialization();\n      }\n\n      private Builder(\n          com.google.protobuf.GeneratedMessage.BuilderParent parent) {\n        super(parent);\n        maybeForceBuilderInitialization();\n      }\n      private void maybeForceBuilderInitialization() {\n        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {\n        }\n      }\n      private static Builder create() {\n        return new Builder();\n      }\n\n      public Builder clear() {\n        super.clear();\n        key_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000001);\n        value_ = \"\";\n        bitField0_ = (bitField0_ & ~0x00000002);\n        return this;\n      }\n\n      public Builder clone() {\n        return create().mergeFrom(buildPartial());\n      }\n\n      public com.google.protobuf.Descriptors.Descriptor\n          getDescriptorForType() {\n        return cn.wildfirechat.proto.WFCMessage.internal_static_StringPair_descriptor;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.StringPair getDefaultInstanceForType() {\n        return cn.wildfirechat.proto.WFCMessage.StringPair.getDefaultInstance();\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.StringPair build() {\n        cn.wildfirechat.proto.WFCMessage.StringPair result = buildPartial();\n        if (!result.isInitialized()) {\n          throw newUninitializedMessageException(result);\n        }\n        return result;\n      }\n\n      public cn.wildfirechat.proto.WFCMessage.StringPair buildPartial() {\n        cn.wildfirechat.proto.WFCMessage.StringPair result = new cn.wildfirechat.proto.WFCMessage.StringPair(this);\n        int from_bitField0_ = bitField0_;\n        int to_bitField0_ = 0;\n        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {\n          to_bitField0_ |= 0x00000001;\n        }\n        result.key_ = key_;\n        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {\n          to_bitField0_ |= 0x00000002;\n        }\n        result.value_ = value_;\n        result.bitField0_ = to_bitField0_;\n        onBuilt();\n        return result;\n      }\n\n      public Builder mergeFrom(com.google.protobuf.Message other) {\n        if (other instanceof cn.wildfirechat.proto.WFCMessage.StringPair) {\n          return mergeFrom((cn.wildfirechat.proto.WFCMessage.StringPair)other);\n        } else {\n          super.mergeFrom(other);\n          return this;\n        }\n      }\n\n      public Builder mergeFrom(cn.wildfirechat.proto.WFCMessage.StringPair other) {\n        if (other == cn.wildfirechat.proto.WFCMessage.StringPair.getDefaultInstance()) return this;\n        if (other.hasKey()) {\n          bitField0_ |= 0x00000001;\n          key_ = other.key_;\n          onChanged();\n        }\n        if (other.hasValue()) {\n          bitField0_ |= 0x00000002;\n          value_ = other.value_;\n          onChanged();\n        }\n        this.mergeUnknownFields(other.getUnknownFields());\n        return this;\n      }\n\n      public final boolean isInitialized() {\n        if (!hasKey()) {\n          \n          return false;\n        }\n        return true;\n      }\n\n      public Builder mergeFrom(\n          com.google.protobuf.CodedInputStream input,\n          com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n          throws java.io.IOException {\n        cn.wildfirechat.proto.WFCMessage.StringPair parsedMessage = null;\n        try {\n          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n        } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n          parsedMessage = (cn.wildfirechat.proto.WFCMessage.StringPair) e.getUnfinishedMessage();\n          throw e;\n        } finally {\n          if (parsedMessage != null) {\n            mergeFrom(parsedMessage);\n          }\n        }\n        return this;\n      }\n      private int bitField0_;\n\n      // required string key = 1;\n      private java.lang.Object key_ = \"\";\n      /**\n       * <code>required string key = 1;</code>\n       */\n      public boolean hasKey() {\n        return ((bitField0_ & 0x00000001) == 0x00000001);\n      }\n      /**\n       * <code>required string key = 1;</code>\n       */\n      public java.lang.String getKey() {\n        java.lang.Object ref = key_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          key_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>required string key = 1;</code>\n       */\n      public com.google.protobuf.ByteString\n          getKeyBytes() {\n        java.lang.Object ref = key_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          key_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>required string key = 1;</code>\n       */\n      public Builder setKey(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        key_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string key = 1;</code>\n       */\n      public Builder clearKey() {\n        bitField0_ = (bitField0_ & ~0x00000001);\n        key_ = getDefaultInstance().getKey();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>required string key = 1;</code>\n       */\n      public Builder setKeyBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000001;\n        key_ = value;\n        onChanged();\n        return this;\n      }\n\n      // optional string value = 2;\n      private java.lang.Object value_ = \"\";\n      /**\n       * <code>optional string value = 2;</code>\n       */\n      public boolean hasValue() {\n        return ((bitField0_ & 0x00000002) == 0x00000002);\n      }\n      /**\n       * <code>optional string value = 2;</code>\n       */\n      public java.lang.String getValue() {\n        java.lang.Object ref = value_;\n        if (!(ref instanceof java.lang.String)) {\n          java.lang.String s = ((com.google.protobuf.ByteString) ref)\n              .toStringUtf8();\n          value_ = s;\n          return s;\n        } else {\n          return (java.lang.String) ref;\n        }\n      }\n      /**\n       * <code>optional string value = 2;</code>\n       */\n      public com.google.protobuf.ByteString\n          getValueBytes() {\n        java.lang.Object ref = value_;\n        if (ref instanceof String) {\n          com.google.protobuf.ByteString b = \n              com.google.protobuf.ByteString.copyFromUtf8(\n                  (java.lang.String) ref);\n          value_ = b;\n          return b;\n        } else {\n          return (com.google.protobuf.ByteString) ref;\n        }\n      }\n      /**\n       * <code>optional string value = 2;</code>\n       */\n      public Builder setValue(\n          java.lang.String value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string value = 2;</code>\n       */\n      public Builder clearValue() {\n        bitField0_ = (bitField0_ & ~0x00000002);\n        value_ = getDefaultInstance().getValue();\n        onChanged();\n        return this;\n      }\n      /**\n       * <code>optional string value = 2;</code>\n       */\n      public Builder setValueBytes(\n          com.google.protobuf.ByteString value) {\n        if (value == null) {\n    throw new NullPointerException();\n  }\n  bitField0_ |= 0x00000002;\n        value_ = value;\n        onChanged();\n        return this;\n      }\n\n      // @@protoc_insertion_point(builder_scope:StringPair)\n    }\n\n    static {\n      defaultInstance = new StringPair(true);\n      defaultInstance.initFields();\n    }\n\n    // @@protoc_insertion_point(class_scope:StringPair)\n  }\n\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_AddFriendRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_AddFriendRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_Conversation_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_Conversation_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_GroupInfo_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_GroupInfo_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_GroupMember_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_GroupMember_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_Group_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_Group_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ChannelMenu_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ChannelMenu_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ChannelMenuList_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ChannelMenuList_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ChannelInfo_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ChannelInfo_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ModifyChannelInfo_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ModifyChannelInfo_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_TransferChannel_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_TransferChannel_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_PullChannelInfo_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_PullChannelInfo_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_PullChannelListener_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_PullChannelListener_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_PullChannelListenerResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_PullChannelListenerResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ListenChannel_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ListenChannel_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_SearchChannelResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_SearchChannelResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_MessageContent_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_MessageContent_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_AddGroupMemberRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_AddGroupMemberRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_CreateGroupRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_CreateGroupRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_DismissGroupRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_DismissGroupRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_FriendRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_FriendRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_GeneralResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_GeneralResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_GetUploadTokenRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_GetUploadTokenRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_GetUploadTokenResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_GetUploadTokenResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_HandleFriendRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_HandleFriendRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_IDBuf_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_IDBuf_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_IDListBuf_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_IDListBuf_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_Message_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_Message_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_User_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_User_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_Robot_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_Robot_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_GetRobotsResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_GetRobotsResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_UploadDeviceTokenRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_UploadDeviceTokenRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ModifyGroupInfoRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ModifyGroupInfoRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_SetGroupManagerRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_SetGroupManagerRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_InfoEntry_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_InfoEntry_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ModifyMyInfoRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ModifyMyInfoRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_NotifyMessage_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_NotifyMessage_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_PullMessageRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_PullMessageRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_PullMessageResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_PullMessageResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_PullGroupInfoResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_PullGroupInfoResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_PullGroupMemberRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_PullGroupMemberRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_PullGroupMemberResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_PullGroupMemberResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_UserRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_UserRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_PullUserRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_PullUserRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_UserResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_UserResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_PullUserResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_PullUserResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_QuitGroupRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_QuitGroupRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_RemoveGroupMemberRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_RemoveGroupMemberRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_TransferGroupRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_TransferGroupRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ModifyGroupMemberAlias_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ModifyGroupMemberAlias_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ModifyGroupMemberExtra_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ModifyGroupMemberExtra_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_UserSettingEntry_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_UserSettingEntry_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ModifyUserSettingReq_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ModifyUserSettingReq_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_Version_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_Version_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_GetUserSettingResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_GetUserSettingResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_Friend_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_Friend_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_GetFriendsResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_GetFriendsResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_GetFriendRequestResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_GetFriendRequestResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ConnectAckPayload_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ConnectAckPayload_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_IMHttpWrapper_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_IMHttpWrapper_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_SearchUserRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_SearchUserRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_SearchUserResult_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_SearchUserResult_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_GetChatroomInfoRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_GetChatroomInfoRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ChatroomInfo_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ChatroomInfo_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_GetChatroomMemberInfoRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_GetChatroomMemberInfoRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ChatroomMemberInfo_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ChatroomMemberInfo_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_INT64Buf_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_INT64Buf_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_NotifyRecallMessage_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_NotifyRecallMessage_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_BlackUserRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_BlackUserRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_RouteRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_RouteRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_RouteResponse_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_RouteResponse_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_GetTokenRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_GetTokenRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_LoadRemoteMessages_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_LoadRemoteMessages_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_MultiCastMessage_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_MultiCastMessage_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_RecallMultiCastMessageRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_RecallMultiCastMessageRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_AuthCodeRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_AuthCodeRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_ApplicationConfigRequest_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_ApplicationConfigRequest_fieldAccessorTable;\n  private static com.google.protobuf.Descriptors.Descriptor\n    internal_static_StringPair_descriptor;\n  private static\n    com.google.protobuf.GeneratedMessage.FieldAccessorTable\n      internal_static_StringPair_fieldAccessorTable;\n\n  public static com.google.protobuf.Descriptors.FileDescriptor\n      getDescriptor() {\n    return descriptor;\n  }\n  private static com.google.protobuf.Descriptors.FileDescriptor\n      descriptor;\n  static {\n    java.lang.String[] descriptorData = {\n      \"\\n\\032wfcmessage_community.proto\\\"E\\n\\020AddFrien\" +\n      \"dRequest\\022\\022\\n\\ntarget_uid\\030\\001 \\002(\\t\\022\\016\\n\\006reason\\030\\002\" +\n      \" \\002(\\t\\022\\r\\n\\005extra\\030\\003 \\001(\\t\\\":\\n\\014Conversation\\022\\014\\n\\004t\" +\n      \"ype\\030\\001 \\002(\\005\\022\\016\\n\\006target\\030\\002 \\002(\\t\\022\\014\\n\\004line\\030\\003 \\002(\\005\\\"\" +\n      \"\\321\\002\\n\\tGroupInfo\\022\\021\\n\\ttarget_id\\030\\001 \\001(\\t\\022\\014\\n\\004name\" +\n      \"\\030\\002 \\002(\\t\\022\\020\\n\\010portrait\\030\\003 \\001(\\t\\022\\r\\n\\005owner\\030\\004 \\001(\\t\\022\" +\n      \"\\014\\n\\004type\\030\\005 \\002(\\005\\022\\024\\n\\014member_count\\030\\006 \\001(\\005\\022\\r\\n\\005e\" +\n      \"xtra\\030\\007 \\001(\\t\\022\\021\\n\\tupdate_dt\\030\\010 \\001(\\003\\022\\030\\n\\020member_\" +\n      \"update_dt\\030\\t \\001(\\003\\022\\014\\n\\004mute\\030\\n \\001(\\005\\022\\021\\n\\tjoin_ty\" +\n      \"pe\\030\\013 \\001(\\005\\022\\024\\n\\014private_chat\\030\\014 \\001(\\005\\022\\022\\n\\nsearch\",\n      \"able\\030\\r \\001(\\005\\022\\030\\n\\020max_member_count\\030\\016 \\001(\\005\\022\\027\\n\\017\" +\n      \"history_message\\030\\017 \\001(\\005\\022\\023\\n\\013super_group\\030\\020 \\001\" +\n      \"(\\005\\022\\017\\n\\007deleted\\030\\021 \\001(\\005\\\"r\\n\\013GroupMember\\022\\021\\n\\tme\" +\n      \"mber_id\\030\\001 \\002(\\t\\022\\r\\n\\005alias\\030\\002 \\001(\\t\\022\\014\\n\\004type\\030\\003 \\002\" +\n      \"(\\005\\022\\021\\n\\tupdate_dt\\030\\004 \\001(\\003\\022\\021\\n\\tcreate_dt\\030\\005 \\001(\\003\" +\n      \"\\022\\r\\n\\005extra\\030\\006 \\001(\\t\\\"F\\n\\005Group\\022\\036\\n\\ngroup_info\\030\\001\" +\n      \" \\002(\\0132\\n.GroupInfo\\022\\035\\n\\007members\\030\\002 \\003(\\0132\\014.Grou\" +\n      \"pMember\\\"\\313\\001\\n\\013ChannelMenu\\022\\014\\n\\004type\\030\\001 \\002(\\t\\022\\014\\n\" +\n      \"\\004name\\030\\002 \\002(\\t\\022\\013\\n\\003key\\030\\003 \\001(\\t\\022\\013\\n\\003url\\030\\004 \\001(\\t\\022\\020\\n\" +\n      \"\\010media_id\\030\\005 \\001(\\t\\022\\022\\n\\narticle_id\\030\\006 \\001(\\t\\022\\016\\n\\006a\",\n      \"pp_id\\030\\007 \\001(\\t\\022\\020\\n\\010app_page\\030\\010 \\001(\\t\\022\\036\\n\\010sub_men\" +\n      \"u\\030\\t \\003(\\0132\\014.ChannelMenu\\022\\017\\n\\007menu_id\\030\\n \\001(\\t\\022\\r\" +\n      \"\\n\\005extra\\030\\013 \\001(\\t\\\"-\\n\\017ChannelMenuList\\022\\032\\n\\004menu\" +\n      \"\\030\\001 \\003(\\0132\\014.ChannelMenu\\\"\\340\\001\\n\\013ChannelInfo\\022\\021\\n\\t\" +\n      \"target_id\\030\\001 \\001(\\t\\022\\014\\n\\004name\\030\\002 \\002(\\t\\022\\020\\n\\010portrai\" +\n      \"t\\030\\003 \\001(\\t\\022\\r\\n\\005owner\\030\\004 \\001(\\t\\022\\016\\n\\006status\\030\\005 \\001(\\005\\022\\014\" +\n      \"\\n\\004desc\\030\\006 \\001(\\t\\022\\r\\n\\005extra\\030\\007 \\001(\\t\\022\\021\\n\\tupdate_dt\" +\n      \"\\030\\010 \\001(\\003\\022\\016\\n\\006secret\\030\\t \\001(\\t\\022\\020\\n\\010callback\\030\\n \\001(\\t\" +\n      \"\\022\\021\\n\\tautomatic\\030\\013 \\001(\\005\\022\\032\\n\\004menu\\030\\014 \\003(\\0132\\014.Chan\" +\n      \"nelMenu\\\"D\\n\\021ModifyChannelInfo\\022\\022\\n\\nchannel_\",\n      \"id\\030\\001 \\002(\\t\\022\\014\\n\\004type\\030\\002 \\002(\\005\\022\\r\\n\\005value\\030\\003 \\002(\\t\\\"8\\n\" +\n      \"\\017TransferChannel\\022\\022\\n\\nchannel_id\\030\\001 \\002(\\t\\022\\021\\n\\t\" +\n      \"new_owner\\030\\002 \\002(\\t\\\"3\\n\\017PullChannelInfo\\022\\022\\n\\nch\" +\n      \"annel_id\\030\\001 \\002(\\t\\022\\014\\n\\004head\\030\\002 \\002(\\003\\\"H\\n\\023PullChan\" +\n      \"nelListener\\022\\022\\n\\nchannel_id\\030\\001 \\002(\\t\\022\\016\\n\\006offse\" +\n      \"t\\030\\002 \\002(\\005\\022\\r\\n\\005count\\030\\003 \\002(\\005\\\"R\\n\\031PullChannelLis\" +\n      \"tenerResult\\022\\023\\n\\013total_count\\030\\001 \\002(\\005\\022\\016\\n\\006offs\" +\n      \"et\\030\\002 \\002(\\005\\022\\020\\n\\010listener\\030\\003 \\003(\\t\\\"3\\n\\rListenChan\" +\n      \"nel\\022\\022\\n\\nchannel_id\\030\\001 \\002(\\t\\022\\016\\n\\006listen\\030\\002 \\002(\\005\\\"\" +\n      \"E\\n\\023SearchChannelResult\\022\\035\\n\\007channel\\030\\001 \\003(\\0132\",\n      \"\\014.ChannelInfo\\022\\017\\n\\007keyword\\030\\002 \\002(\\t\\\"\\235\\002\\n\\016Messa\" +\n      \"geContent\\022\\014\\n\\004type\\030\\001 \\002(\\005\\022\\032\\n\\022searchable_co\" +\n      \"ntent\\030\\002 \\001(\\t\\022\\024\\n\\014push_content\\030\\003 \\001(\\t\\022\\017\\n\\007con\" +\n      \"tent\\030\\004 \\001(\\t\\022\\014\\n\\004data\\030\\005 \\001(\\014\\022\\021\\n\\tmediaType\\030\\006 \" +\n      \"\\001(\\005\\022\\026\\n\\016remoteMediaUrl\\030\\007 \\001(\\t\\022\\024\\n\\014persist_f\" +\n      \"lag\\030\\010 \\001(\\005\\022\\027\\n\\017expire_duration\\030\\t \\001(\\005\\022\\026\\n\\016me\" +\n      \"ntioned_type\\030\\n \\001(\\005\\022\\030\\n\\020mentioned_target\\030\\013\" +\n      \" \\003(\\t\\022\\r\\n\\005extra\\030\\014 \\001(\\t\\022\\021\\n\\tpush_data\\030\\r \\001(\\t\\\"\\226\" +\n      \"\\001\\n\\025AddGroupMemberRequest\\022\\020\\n\\010group_id\\030\\001 \\002\" +\n      \"(\\t\\022\\\"\\n\\014added_member\\030\\002 \\003(\\0132\\014.GroupMember\\022\\017\",\n      \"\\n\\007to_line\\030\\003 \\003(\\005\\022\\'\\n\\016notify_content\\030\\004 \\001(\\0132\" +\n      \"\\017.MessageContent\\022\\r\\n\\005extra\\030\\005 \\001(\\t\\\"{\\n\\022Creat\" +\n      \"eGroupRequest\\022\\025\\n\\005group\\030\\001 \\002(\\0132\\006.Group\\022\\017\\n\\007\" +\n      \"to_line\\030\\002 \\003(\\005\\022\\'\\n\\016notify_content\\030\\003 \\001(\\0132\\017.\" +\n      \"MessageContent\\022\\024\\n\\014member_extra\\030\\004 \\001(\\t\\\"a\\n\\023\" +\n      \"DismissGroupRequest\\022\\020\\n\\010group_id\\030\\001 \\002(\\t\\022\\017\\n\" +\n      \"\\007to_line\\030\\002 \\003(\\005\\022\\'\\n\\016notify_content\\030\\003 \\001(\\0132\\017\" +\n      \".MessageContent\\\"\\245\\001\\n\\rFriendRequest\\022\\020\\n\\010fro\" +\n      \"m_uid\\030\\001 \\001(\\t\\022\\016\\n\\006to_uid\\030\\002 \\002(\\t\\022\\016\\n\\006reason\\030\\003 \" +\n      \"\\002(\\t\\022\\016\\n\\006status\\030\\004 \\001(\\005\\022\\021\\n\\tupdate_dt\\030\\005 \\001(\\003\\022\\030\",\n      \"\\n\\020from_read_status\\030\\006 \\001(\\010\\022\\026\\n\\016to_read_stat\" +\n      \"us\\030\\007 \\001(\\010\\022\\r\\n\\005extra\\030\\010 \\001(\\t\\\"#\\n\\rGeneralResult\" +\n      \"\\022\\022\\n\\nerror_code\\030\\001 \\002(\\005\\\"?\\n\\025GetUploadTokenRe\" +\n      \"quest\\022\\022\\n\\nmedia_type\\030\\001 \\002(\\005\\022\\022\\n\\nmedia_path\\030\" +\n      \"\\002 \\002(\\t\\\"S\\n\\024GetUploadTokenResult\\022\\016\\n\\006domain\\030\" +\n      \"\\001 \\002(\\t\\022\\r\\n\\005token\\030\\002 \\002(\\t\\022\\016\\n\\006server\\030\\003 \\002(\\t\\022\\014\\n\\004\" +\n      \"port\\030\\004 \\001(\\005\\\"H\\n\\023HandleFriendRequest\\022\\022\\n\\ntar\" +\n      \"get_uid\\030\\001 \\002(\\t\\022\\016\\n\\006status\\030\\002 \\002(\\005\\022\\r\\n\\005extra\\030\\003\" +\n      \" \\001(\\t\\\"\\023\\n\\005IDBuf\\022\\n\\n\\002id\\030\\001 \\002(\\t\\\"\\027\\n\\tIDListBuf\\022\\n\" +\n      \"\\n\\002id\\030\\001 \\003(\\t\\\"\\256\\001\\n\\007Message\\022#\\n\\014conversation\\030\\001\",\n      \" \\002(\\0132\\r.Conversation\\022\\021\\n\\tfrom_user\\030\\002 \\002(\\t\\022 \" +\n      \"\\n\\007content\\030\\003 \\002(\\0132\\017.MessageContent\\022\\022\\n\\nmess\" +\n      \"age_id\\030\\004 \\001(\\003\\022\\030\\n\\020server_timestamp\\030\\005 \\001(\\003\\022\\017\" +\n      \"\\n\\007to_user\\030\\006 \\001(\\t\\022\\n\\n\\002to\\030\\007 \\003(\\t\\\"\\353\\001\\n\\004User\\022\\013\\n\\003\" +\n      \"uid\\030\\001 \\002(\\t\\022\\014\\n\\004name\\030\\002 \\001(\\t\\022\\024\\n\\014display_name\\030\" +\n      \"\\003 \\001(\\t\\022\\020\\n\\010portrait\\030\\004 \\001(\\t\\022\\016\\n\\006mobile\\030\\005 \\001(\\t\\022\" +\n      \"\\r\\n\\005email\\030\\006 \\001(\\t\\022\\017\\n\\007address\\030\\007 \\001(\\t\\022\\017\\n\\007compa\" +\n      \"ny\\030\\010 \\001(\\t\\022\\r\\n\\005extra\\030\\t \\001(\\t\\022\\021\\n\\tupdate_dt\\030\\n \\001\" +\n      \"(\\003\\022\\016\\n\\006gender\\030\\013 \\001(\\005\\022\\016\\n\\006social\\030\\014 \\001(\\t\\022\\014\\n\\004ty\" +\n      \"pe\\030\\r \\001(\\005\\022\\017\\n\\007deleted\\030\\016 \\001(\\005\\\"c\\n\\005Robot\\022\\013\\n\\003ui\",\n      \"d\\030\\001 \\002(\\t\\022\\r\\n\\005state\\030\\002 \\002(\\005\\022\\r\\n\\005owner\\030\\003 \\001(\\t\\022\\016\\n\" +\n      \"\\006secret\\030\\004 \\001(\\t\\022\\020\\n\\010callback\\030\\005 \\001(\\t\\022\\r\\n\\005extra\" +\n      \"\\030\\006 \\001(\\t\\\"(\\n\\017GetRobotsResult\\022\\025\\n\\005entry\\030\\001 \\003(\\013\" +\n      \"2\\006.Robot\\\"g\\n\\030UploadDeviceTokenRequest\\022\\020\\n\\010\" +\n      \"platform\\030\\001 \\002(\\005\\022\\020\\n\\010app_name\\030\\002 \\002(\\t\\022\\024\\n\\014devi\" +\n      \"ce_token\\030\\003 \\002(\\t\\022\\021\\n\\tpush_type\\030\\004 \\002(\\005\\\"\\201\\001\\n\\026Mo\" +\n      \"difyGroupInfoRequest\\022\\020\\n\\010group_id\\030\\001 \\002(\\t\\022\\014\" +\n      \"\\n\\004type\\030\\002 \\002(\\005\\022\\r\\n\\005value\\030\\003 \\002(\\t\\022\\017\\n\\007to_line\\030\\004\" +\n      \" \\003(\\005\\022\\'\\n\\016notify_content\\030\\005 \\001(\\0132\\017.MessageCo\" +\n      \"ntent\\\"\\203\\001\\n\\026SetGroupManagerRequest\\022\\020\\n\\010grou\",\n      \"p_id\\030\\001 \\002(\\t\\022\\014\\n\\004type\\030\\002 \\002(\\005\\022\\017\\n\\007user_id\\030\\003 \\003(\" +\n      \"\\t\\022\\017\\n\\007to_line\\030\\004 \\003(\\005\\022\\'\\n\\016notify_content\\030\\005 \\001\" +\n      \"(\\0132\\017.MessageContent\\\"(\\n\\tInfoEntry\\022\\014\\n\\004type\" +\n      \"\\030\\001 \\002(\\005\\022\\r\\n\\005value\\030\\002 \\002(\\t\\\"0\\n\\023ModifyMyInfoReq\" +\n      \"uest\\022\\031\\n\\005entry\\030\\001 \\003(\\0132\\n.InfoEntry\\\";\\n\\rNotif\" +\n      \"yMessage\\022\\014\\n\\004type\\030\\001 \\002(\\005\\022\\014\\n\\004head\\030\\002 \\002(\\003\\022\\016\\n\\006\" +\n      \"target\\030\\003 \\001(\\t\\\"=\\n\\022PullMessageRequest\\022\\n\\n\\002id\" +\n      \"\\030\\001 \\002(\\003\\022\\014\\n\\004type\\030\\002 \\002(\\005\\022\\r\\n\\005delay\\030\\003 \\001(\\003\\\"M\\n\\021P\" +\n      \"ullMessageResult\\022\\031\\n\\007message\\030\\001 \\003(\\0132\\010.Mess\" +\n      \"age\\022\\017\\n\\007current\\030\\002 \\002(\\003\\022\\014\\n\\004head\\030\\003 \\002(\\003\\\"/\\n\\023Pu\",\n      \"llGroupInfoResult\\022\\030\\n\\004info\\030\\001 \\003(\\0132\\n.GroupI\" +\n      \"nfo\\\"6\\n\\026PullGroupMemberRequest\\022\\016\\n\\006target\\030\" +\n      \"\\001 \\002(\\t\\022\\014\\n\\004head\\030\\002 \\002(\\003\\\"5\\n\\025PullGroupMemberRe\" +\n      \"sult\\022\\034\\n\\006member\\030\\001 \\003(\\0132\\014.GroupMember\\\"-\\n\\013Us\" +\n      \"erRequest\\022\\013\\n\\003uid\\030\\001 \\002(\\t\\022\\021\\n\\tupdate_dt\\030\\002 \\001(\" +\n      \"\\003\\\"0\\n\\017PullUserRequest\\022\\035\\n\\007request\\030\\001 \\003(\\0132\\014.\" +\n      \"UserRequest\\\"/\\n\\nUserResult\\022\\023\\n\\004user\\030\\001 \\002(\\0132\" +\n      \"\\005.User\\022\\014\\n\\004code\\030\\002 \\002(\\005\\\"-\\n\\016PullUserResult\\022\\033\" +\n      \"\\n\\006result\\030\\001 \\003(\\0132\\013.UserResult\\\"p\\n\\020QuitGroup\" +\n      \"Request\\022\\020\\n\\010group_id\\030\\001 \\002(\\t\\022\\017\\n\\007to_line\\030\\002 \\003\",\n      \"(\\005\\022\\'\\n\\016notify_content\\030\\003 \\001(\\0132\\017.MessageCont\" +\n      \"ent\\022\\020\\n\\010keep_msg\\030\\004 \\001(\\005\\\"~\\n\\030RemoveGroupMemb\" +\n      \"erRequest\\022\\020\\n\\010group_id\\030\\001 \\002(\\t\\022\\026\\n\\016removed_m\" +\n      \"ember\\030\\002 \\003(\\t\\022\\017\\n\\007to_line\\030\\003 \\003(\\005\\022\\'\\n\\016notify_c\" +\n      \"ontent\\030\\004 \\001(\\0132\\017.MessageContent\\\"u\\n\\024Transfe\" +\n      \"rGroupRequest\\022\\020\\n\\010group_id\\030\\001 \\002(\\t\\022\\021\\n\\tnew_o\" +\n      \"wner\\030\\002 \\002(\\t\\022\\017\\n\\007to_line\\030\\003 \\003(\\005\\022\\'\\n\\016notify_co\" +\n      \"ntent\\030\\004 \\001(\\0132\\017.MessageContent\\\"\\206\\001\\n\\026ModifyG\" +\n      \"roupMemberAlias\\022\\020\\n\\010group_id\\030\\001 \\002(\\t\\022\\r\\n\\005ali\" +\n      \"as\\030\\002 \\002(\\t\\022\\017\\n\\007to_line\\030\\003 \\003(\\005\\022\\'\\n\\016notify_cont\",\n      \"ent\\030\\004 \\001(\\0132\\017.MessageContent\\022\\021\\n\\tmember_id\\030\" +\n      \"\\005 \\001(\\t\\\"\\206\\001\\n\\026ModifyGroupMemberExtra\\022\\020\\n\\010grou\" +\n      \"p_id\\030\\001 \\002(\\t\\022\\017\\n\\007to_line\\030\\002 \\003(\\005\\022\\'\\n\\016notify_co\" +\n      \"ntent\\030\\003 \\001(\\0132\\017.MessageContent\\022\\r\\n\\005extra\\030\\004 \" +\n      \"\\001(\\t\\022\\021\\n\\tmember_id\\030\\005 \\001(\\t\\\"P\\n\\020UserSettingEnt\" +\n      \"ry\\022\\r\\n\\005scope\\030\\001 \\002(\\005\\022\\013\\n\\003key\\030\\002 \\002(\\t\\022\\r\\n\\005value\\030\" +\n      \"\\003 \\002(\\t\\022\\021\\n\\tupdate_dt\\030\\004 \\002(\\003\\\"A\\n\\024ModifyUserSe\" +\n      \"ttingReq\\022\\r\\n\\005scope\\030\\001 \\002(\\005\\022\\013\\n\\003key\\030\\002 \\002(\\t\\022\\r\\n\\005\" +\n      \"value\\030\\003 \\002(\\t\\\"\\032\\n\\007Version\\022\\017\\n\\007version\\030\\001 \\002(\\003\\\"\" +\n      \"8\\n\\024GetUserSettingResult\\022 \\n\\005entry\\030\\001 \\003(\\0132\\021\",\n      \".UserSettingEntry\\\"f\\n\\006Friend\\022\\013\\n\\003uid\\030\\001 \\002(\\t\" +\n      \"\\022\\r\\n\\005state\\030\\002 \\002(\\005\\022\\021\\n\\tupdate_dt\\030\\003 \\002(\\003\\022\\r\\n\\005al\" +\n      \"ias\\030\\004 \\001(\\t\\022\\017\\n\\007blacked\\030\\005 \\001(\\005\\022\\r\\n\\005extra\\030\\006 \\001(\" +\n      \"\\t\\\"*\\n\\020GetFriendsResult\\022\\026\\n\\005entry\\030\\001 \\003(\\0132\\007.F\" +\n      \"riend\\\"7\\n\\026GetFriendRequestResult\\022\\035\\n\\005entry\" +\n      \"\\030\\001 \\003(\\0132\\016.FriendRequest\\\"\\243\\001\\n\\021ConnectAckPay\" +\n      \"load\\022\\020\\n\\010msg_head\\030\\001 \\001(\\003\\022\\023\\n\\013friend_head\\030\\002 \" +\n      \"\\001(\\003\\022\\026\\n\\016friend_rq_head\\030\\003 \\001(\\003\\022\\024\\n\\014setting_h\" +\n      \"ead\\030\\004 \\001(\\003\\022\\021\\n\\tnode_addr\\030\\005 \\001(\\t\\022\\021\\n\\tnode_por\" +\n      \"t\\030\\006 \\001(\\005\\022\\023\\n\\013server_time\\030\\007 \\001(\\003\\\"P\\n\\rIMHttpWr\",\n      \"apper\\022\\r\\n\\005token\\030\\001 \\002(\\t\\022\\021\\n\\tclient_id\\030\\002 \\002(\\t\\022\" +\n      \"\\017\\n\\007request\\030\\003 \\002(\\t\\022\\014\\n\\004data\\030\\004 \\001(\\014\\\"b\\n\\021Search\" +\n      \"UserRequest\\022\\017\\n\\007keyword\\030\\001 \\002(\\t\\022\\r\\n\\005fuzzy\\030\\002 \" +\n      \"\\001(\\005\\022\\014\\n\\004page\\030\\003 \\001(\\005\\022\\021\\n\\tdomain_id\\030\\004 \\001(\\t\\022\\014\\n\\004\" +\n      \"type\\030\\005 \\001(\\005\\\"(\\n\\020SearchUserResult\\022\\024\\n\\005entry\\030\" +\n      \"\\001 \\003(\\0132\\005.User\\\"@\\n\\026GetChatroomInfoRequest\\022\\023\" +\n      \"\\n\\013chatroom_id\\030\\001 \\002(\\t\\022\\021\\n\\tupdate_dt\\030\\002 \\001(\\003\\\"\\227\" +\n      \"\\001\\n\\014ChatroomInfo\\022\\r\\n\\005title\\030\\001 \\002(\\t\\022\\014\\n\\004desc\\030\\002\" +\n      \" \\001(\\t\\022\\020\\n\\010portrait\\030\\003 \\001(\\t\\022\\024\\n\\014member_count\\030\\004\" +\n      \" \\001(\\005\\022\\021\\n\\tcreate_dt\\030\\005 \\001(\\003\\022\\021\\n\\tupdate_dt\\030\\006 \\001\",\n      \"(\\003\\022\\r\\n\\005extra\\030\\007 \\001(\\t\\022\\r\\n\\005state\\030\\010 \\001(\\005\\\"F\\n\\034GetC\" +\n      \"hatroomMemberInfoRequest\\022\\023\\n\\013chatroom_id\\030\" +\n      \"\\001 \\002(\\t\\022\\021\\n\\tmax_count\\030\\002 \\001(\\005\\\";\\n\\022ChatroomMemb\" +\n      \"erInfo\\022\\024\\n\\014member_count\\030\\001 \\001(\\005\\022\\017\\n\\007members\\030\" +\n      \"\\002 \\003(\\t\\\"\\026\\n\\010INT64Buf\\022\\n\\n\\002id\\030\\001 \\002(\\003\\\"4\\n\\023NotifyR\" +\n      \"ecallMessage\\022\\n\\n\\002id\\030\\001 \\002(\\003\\022\\021\\n\\tfrom_user\\030\\002 \" +\n      \"\\002(\\t\\\"/\\n\\020BlackUserRequest\\022\\013\\n\\003uid\\030\\001 \\002(\\t\\022\\016\\n\\006\" +\n      \"status\\030\\002 \\002(\\005\\\"\\323\\001\\n\\014RouteRequest\\022\\013\\n\\003app\\030\\001 \\001\" +\n      \"(\\t\\022\\020\\n\\010platform\\030\\002 \\001(\\005\\022\\021\\n\\tpush_type\\030\\003 \\001(\\005\\022\" +\n      \"\\023\\n\\013device_name\\030\\004 \\001(\\t\\022\\026\\n\\016device_version\\030\\005\",\n      \" \\001(\\t\\022\\022\\n\\nphone_name\\030\\006 \\001(\\t\\022\\020\\n\\010language\\030\\007 \\001\" +\n      \"(\\t\\022\\024\\n\\014carrier_name\\030\\010 \\001(\\t\\022\\023\\n\\013app_version\\030\" +\n      \"\\t \\001(\\t\\022\\023\\n\\013sdk_version\\030\\n \\001(\\t\\\"D\\n\\rRouteRespo\" +\n      \"nse\\022\\014\\n\\004host\\030\\001 \\002(\\t\\022\\021\\n\\tlong_port\\030\\002 \\002(\\005\\022\\022\\n\\n\" +\n      \"short_port\\030\\003 \\002(\\005\\\"G\\n\\017GetTokenRequest\\022\\017\\n\\007u\" +\n      \"ser_id\\030\\001 \\002(\\t\\022\\021\\n\\tclient_id\\030\\002 \\002(\\t\\022\\020\\n\\010platf\" +\n      \"orm\\030\\003 \\001(\\005\\\"r\\n\\022LoadRemoteMessages\\022#\\n\\014conve\" +\n      \"rsation\\030\\001 \\002(\\0132\\r.Conversation\\022\\022\\n\\nbefore_u\" +\n      \"id\\030\\002 \\002(\\003\\022\\r\\n\\005count\\030\\003 \\002(\\005\\022\\024\\n\\014content_type\\030\" +\n      \"\\004 \\003(\\005\\\"a\\n\\020MultiCastMessage\\022\\021\\n\\tfrom_user\\030\\001\",\n      \" \\002(\\t\\022 \\n\\007content\\030\\002 \\002(\\0132\\017.MessageContent\\022\\n\" +\n      \"\\n\\002to\\030\\003 \\003(\\t\\022\\014\\n\\004line\\030\\004 \\002(\\005\\\"E\\n\\035RecallMultiC\" +\n      \"astMessageRequest\\022\\022\\n\\nmessage_id\\030\\001 \\002(\\003\\022\\020\\n\" +\n      \"\\010receiver\\030\\002 \\003(\\t\\\"@\\n\\017AuthCodeRequest\\022\\021\\n\\tta\" +\n      \"rget_id\\030\\001 \\002(\\t\\022\\014\\n\\004type\\030\\002 \\002(\\005\\022\\014\\n\\004host\\030\\003 \\002(\" +\n      \"\\t\\\"o\\n\\030ApplicationConfigRequest\\022\\r\\n\\005appId\\030\\001\" +\n      \" \\002(\\t\\022\\017\\n\\007appType\\030\\002 \\002(\\005\\022\\021\\n\\ttimestamp\\030\\003 \\002(\\003\" +\n      \"\\022\\r\\n\\005nonce\\030\\004 \\002(\\t\\022\\021\\n\\tsignature\\030\\005 \\002(\\t\\\"(\\n\\nSt\" +\n      \"ringPair\\022\\013\\n\\003key\\030\\001 \\002(\\t\\022\\r\\n\\005value\\030\\002 \\001(\\tB/\\n\\025\" +\n      \"cn.wildfirechat.protoB\\nWFCMessageZ\\n./go;\",\n      \"proto\"\n    };\n    com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =\n      new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {\n        public com.google.protobuf.ExtensionRegistry assignDescriptors(\n            com.google.protobuf.Descriptors.FileDescriptor root) {\n          descriptor = root;\n          internal_static_AddFriendRequest_descriptor =\n            getDescriptor().getMessageTypes().get(0);\n          internal_static_AddFriendRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_AddFriendRequest_descriptor,\n              new java.lang.String[] { \"TargetUid\", \"Reason\", \"Extra\", });\n          internal_static_Conversation_descriptor =\n            getDescriptor().getMessageTypes().get(1);\n          internal_static_Conversation_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_Conversation_descriptor,\n              new java.lang.String[] { \"Type\", \"Target\", \"Line\", });\n          internal_static_GroupInfo_descriptor =\n            getDescriptor().getMessageTypes().get(2);\n          internal_static_GroupInfo_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_GroupInfo_descriptor,\n              new java.lang.String[] { \"TargetId\", \"Name\", \"Portrait\", \"Owner\", \"Type\", \"MemberCount\", \"Extra\", \"UpdateDt\", \"MemberUpdateDt\", \"Mute\", \"JoinType\", \"PrivateChat\", \"Searchable\", \"MaxMemberCount\", \"HistoryMessage\", \"SuperGroup\", \"Deleted\", });\n          internal_static_GroupMember_descriptor =\n            getDescriptor().getMessageTypes().get(3);\n          internal_static_GroupMember_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_GroupMember_descriptor,\n              new java.lang.String[] { \"MemberId\", \"Alias\", \"Type\", \"UpdateDt\", \"CreateDt\", \"Extra\", });\n          internal_static_Group_descriptor =\n            getDescriptor().getMessageTypes().get(4);\n          internal_static_Group_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_Group_descriptor,\n              new java.lang.String[] { \"GroupInfo\", \"Members\", });\n          internal_static_ChannelMenu_descriptor =\n            getDescriptor().getMessageTypes().get(5);\n          internal_static_ChannelMenu_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ChannelMenu_descriptor,\n              new java.lang.String[] { \"Type\", \"Name\", \"Key\", \"Url\", \"MediaId\", \"ArticleId\", \"AppId\", \"AppPage\", \"SubMenu\", \"MenuId\", \"Extra\", });\n          internal_static_ChannelMenuList_descriptor =\n            getDescriptor().getMessageTypes().get(6);\n          internal_static_ChannelMenuList_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ChannelMenuList_descriptor,\n              new java.lang.String[] { \"Menu\", });\n          internal_static_ChannelInfo_descriptor =\n            getDescriptor().getMessageTypes().get(7);\n          internal_static_ChannelInfo_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ChannelInfo_descriptor,\n              new java.lang.String[] { \"TargetId\", \"Name\", \"Portrait\", \"Owner\", \"Status\", \"Desc\", \"Extra\", \"UpdateDt\", \"Secret\", \"Callback\", \"Automatic\", \"Menu\", });\n          internal_static_ModifyChannelInfo_descriptor =\n            getDescriptor().getMessageTypes().get(8);\n          internal_static_ModifyChannelInfo_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ModifyChannelInfo_descriptor,\n              new java.lang.String[] { \"ChannelId\", \"Type\", \"Value\", });\n          internal_static_TransferChannel_descriptor =\n            getDescriptor().getMessageTypes().get(9);\n          internal_static_TransferChannel_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_TransferChannel_descriptor,\n              new java.lang.String[] { \"ChannelId\", \"NewOwner\", });\n          internal_static_PullChannelInfo_descriptor =\n            getDescriptor().getMessageTypes().get(10);\n          internal_static_PullChannelInfo_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_PullChannelInfo_descriptor,\n              new java.lang.String[] { \"ChannelId\", \"Head\", });\n          internal_static_PullChannelListener_descriptor =\n            getDescriptor().getMessageTypes().get(11);\n          internal_static_PullChannelListener_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_PullChannelListener_descriptor,\n              new java.lang.String[] { \"ChannelId\", \"Offset\", \"Count\", });\n          internal_static_PullChannelListenerResult_descriptor =\n            getDescriptor().getMessageTypes().get(12);\n          internal_static_PullChannelListenerResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_PullChannelListenerResult_descriptor,\n              new java.lang.String[] { \"TotalCount\", \"Offset\", \"Listener\", });\n          internal_static_ListenChannel_descriptor =\n            getDescriptor().getMessageTypes().get(13);\n          internal_static_ListenChannel_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ListenChannel_descriptor,\n              new java.lang.String[] { \"ChannelId\", \"Listen\", });\n          internal_static_SearchChannelResult_descriptor =\n            getDescriptor().getMessageTypes().get(14);\n          internal_static_SearchChannelResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_SearchChannelResult_descriptor,\n              new java.lang.String[] { \"Channel\", \"Keyword\", });\n          internal_static_MessageContent_descriptor =\n            getDescriptor().getMessageTypes().get(15);\n          internal_static_MessageContent_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_MessageContent_descriptor,\n              new java.lang.String[] { \"Type\", \"SearchableContent\", \"PushContent\", \"Content\", \"Data\", \"MediaType\", \"RemoteMediaUrl\", \"PersistFlag\", \"ExpireDuration\", \"MentionedType\", \"MentionedTarget\", \"Extra\", \"PushData\", });\n          internal_static_AddGroupMemberRequest_descriptor =\n            getDescriptor().getMessageTypes().get(16);\n          internal_static_AddGroupMemberRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_AddGroupMemberRequest_descriptor,\n              new java.lang.String[] { \"GroupId\", \"AddedMember\", \"ToLine\", \"NotifyContent\", \"Extra\", });\n          internal_static_CreateGroupRequest_descriptor =\n            getDescriptor().getMessageTypes().get(17);\n          internal_static_CreateGroupRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_CreateGroupRequest_descriptor,\n              new java.lang.String[] { \"Group\", \"ToLine\", \"NotifyContent\", \"MemberExtra\", });\n          internal_static_DismissGroupRequest_descriptor =\n            getDescriptor().getMessageTypes().get(18);\n          internal_static_DismissGroupRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_DismissGroupRequest_descriptor,\n              new java.lang.String[] { \"GroupId\", \"ToLine\", \"NotifyContent\", });\n          internal_static_FriendRequest_descriptor =\n            getDescriptor().getMessageTypes().get(19);\n          internal_static_FriendRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_FriendRequest_descriptor,\n              new java.lang.String[] { \"FromUid\", \"ToUid\", \"Reason\", \"Status\", \"UpdateDt\", \"FromReadStatus\", \"ToReadStatus\", \"Extra\", });\n          internal_static_GeneralResult_descriptor =\n            getDescriptor().getMessageTypes().get(20);\n          internal_static_GeneralResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_GeneralResult_descriptor,\n              new java.lang.String[] { \"ErrorCode\", });\n          internal_static_GetUploadTokenRequest_descriptor =\n            getDescriptor().getMessageTypes().get(21);\n          internal_static_GetUploadTokenRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_GetUploadTokenRequest_descriptor,\n              new java.lang.String[] { \"MediaType\", \"MediaPath\", });\n          internal_static_GetUploadTokenResult_descriptor =\n            getDescriptor().getMessageTypes().get(22);\n          internal_static_GetUploadTokenResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_GetUploadTokenResult_descriptor,\n              new java.lang.String[] { \"Domain\", \"Token\", \"Server\", \"Port\", });\n          internal_static_HandleFriendRequest_descriptor =\n            getDescriptor().getMessageTypes().get(23);\n          internal_static_HandleFriendRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_HandleFriendRequest_descriptor,\n              new java.lang.String[] { \"TargetUid\", \"Status\", \"Extra\", });\n          internal_static_IDBuf_descriptor =\n            getDescriptor().getMessageTypes().get(24);\n          internal_static_IDBuf_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_IDBuf_descriptor,\n              new java.lang.String[] { \"Id\", });\n          internal_static_IDListBuf_descriptor =\n            getDescriptor().getMessageTypes().get(25);\n          internal_static_IDListBuf_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_IDListBuf_descriptor,\n              new java.lang.String[] { \"Id\", });\n          internal_static_Message_descriptor =\n            getDescriptor().getMessageTypes().get(26);\n          internal_static_Message_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_Message_descriptor,\n              new java.lang.String[] { \"Conversation\", \"FromUser\", \"Content\", \"MessageId\", \"ServerTimestamp\", \"ToUser\", \"To\", });\n          internal_static_User_descriptor =\n            getDescriptor().getMessageTypes().get(27);\n          internal_static_User_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_User_descriptor,\n              new java.lang.String[] { \"Uid\", \"Name\", \"DisplayName\", \"Portrait\", \"Mobile\", \"Email\", \"Address\", \"Company\", \"Extra\", \"UpdateDt\", \"Gender\", \"Social\", \"Type\", \"Deleted\", });\n          internal_static_Robot_descriptor =\n            getDescriptor().getMessageTypes().get(28);\n          internal_static_Robot_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_Robot_descriptor,\n              new java.lang.String[] { \"Uid\", \"State\", \"Owner\", \"Secret\", \"Callback\", \"Extra\", });\n          internal_static_GetRobotsResult_descriptor =\n            getDescriptor().getMessageTypes().get(29);\n          internal_static_GetRobotsResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_GetRobotsResult_descriptor,\n              new java.lang.String[] { \"Entry\", });\n          internal_static_UploadDeviceTokenRequest_descriptor =\n            getDescriptor().getMessageTypes().get(30);\n          internal_static_UploadDeviceTokenRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_UploadDeviceTokenRequest_descriptor,\n              new java.lang.String[] { \"Platform\", \"AppName\", \"DeviceToken\", \"PushType\", });\n          internal_static_ModifyGroupInfoRequest_descriptor =\n            getDescriptor().getMessageTypes().get(31);\n          internal_static_ModifyGroupInfoRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ModifyGroupInfoRequest_descriptor,\n              new java.lang.String[] { \"GroupId\", \"Type\", \"Value\", \"ToLine\", \"NotifyContent\", });\n          internal_static_SetGroupManagerRequest_descriptor =\n            getDescriptor().getMessageTypes().get(32);\n          internal_static_SetGroupManagerRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_SetGroupManagerRequest_descriptor,\n              new java.lang.String[] { \"GroupId\", \"Type\", \"UserId\", \"ToLine\", \"NotifyContent\", });\n          internal_static_InfoEntry_descriptor =\n            getDescriptor().getMessageTypes().get(33);\n          internal_static_InfoEntry_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_InfoEntry_descriptor,\n              new java.lang.String[] { \"Type\", \"Value\", });\n          internal_static_ModifyMyInfoRequest_descriptor =\n            getDescriptor().getMessageTypes().get(34);\n          internal_static_ModifyMyInfoRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ModifyMyInfoRequest_descriptor,\n              new java.lang.String[] { \"Entry\", });\n          internal_static_NotifyMessage_descriptor =\n            getDescriptor().getMessageTypes().get(35);\n          internal_static_NotifyMessage_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_NotifyMessage_descriptor,\n              new java.lang.String[] { \"Type\", \"Head\", \"Target\", });\n          internal_static_PullMessageRequest_descriptor =\n            getDescriptor().getMessageTypes().get(36);\n          internal_static_PullMessageRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_PullMessageRequest_descriptor,\n              new java.lang.String[] { \"Id\", \"Type\", \"Delay\", });\n          internal_static_PullMessageResult_descriptor =\n            getDescriptor().getMessageTypes().get(37);\n          internal_static_PullMessageResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_PullMessageResult_descriptor,\n              new java.lang.String[] { \"Message\", \"Current\", \"Head\", });\n          internal_static_PullGroupInfoResult_descriptor =\n            getDescriptor().getMessageTypes().get(38);\n          internal_static_PullGroupInfoResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_PullGroupInfoResult_descriptor,\n              new java.lang.String[] { \"Info\", });\n          internal_static_PullGroupMemberRequest_descriptor =\n            getDescriptor().getMessageTypes().get(39);\n          internal_static_PullGroupMemberRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_PullGroupMemberRequest_descriptor,\n              new java.lang.String[] { \"Target\", \"Head\", });\n          internal_static_PullGroupMemberResult_descriptor =\n            getDescriptor().getMessageTypes().get(40);\n          internal_static_PullGroupMemberResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_PullGroupMemberResult_descriptor,\n              new java.lang.String[] { \"Member\", });\n          internal_static_UserRequest_descriptor =\n            getDescriptor().getMessageTypes().get(41);\n          internal_static_UserRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_UserRequest_descriptor,\n              new java.lang.String[] { \"Uid\", \"UpdateDt\", });\n          internal_static_PullUserRequest_descriptor =\n            getDescriptor().getMessageTypes().get(42);\n          internal_static_PullUserRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_PullUserRequest_descriptor,\n              new java.lang.String[] { \"Request\", });\n          internal_static_UserResult_descriptor =\n            getDescriptor().getMessageTypes().get(43);\n          internal_static_UserResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_UserResult_descriptor,\n              new java.lang.String[] { \"User\", \"Code\", });\n          internal_static_PullUserResult_descriptor =\n            getDescriptor().getMessageTypes().get(44);\n          internal_static_PullUserResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_PullUserResult_descriptor,\n              new java.lang.String[] { \"Result\", });\n          internal_static_QuitGroupRequest_descriptor =\n            getDescriptor().getMessageTypes().get(45);\n          internal_static_QuitGroupRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_QuitGroupRequest_descriptor,\n              new java.lang.String[] { \"GroupId\", \"ToLine\", \"NotifyContent\", \"KeepMsg\", });\n          internal_static_RemoveGroupMemberRequest_descriptor =\n            getDescriptor().getMessageTypes().get(46);\n          internal_static_RemoveGroupMemberRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_RemoveGroupMemberRequest_descriptor,\n              new java.lang.String[] { \"GroupId\", \"RemovedMember\", \"ToLine\", \"NotifyContent\", });\n          internal_static_TransferGroupRequest_descriptor =\n            getDescriptor().getMessageTypes().get(47);\n          internal_static_TransferGroupRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_TransferGroupRequest_descriptor,\n              new java.lang.String[] { \"GroupId\", \"NewOwner\", \"ToLine\", \"NotifyContent\", });\n          internal_static_ModifyGroupMemberAlias_descriptor =\n            getDescriptor().getMessageTypes().get(48);\n          internal_static_ModifyGroupMemberAlias_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ModifyGroupMemberAlias_descriptor,\n              new java.lang.String[] { \"GroupId\", \"Alias\", \"ToLine\", \"NotifyContent\", \"MemberId\", });\n          internal_static_ModifyGroupMemberExtra_descriptor =\n            getDescriptor().getMessageTypes().get(49);\n          internal_static_ModifyGroupMemberExtra_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ModifyGroupMemberExtra_descriptor,\n              new java.lang.String[] { \"GroupId\", \"ToLine\", \"NotifyContent\", \"Extra\", \"MemberId\", });\n          internal_static_UserSettingEntry_descriptor =\n            getDescriptor().getMessageTypes().get(50);\n          internal_static_UserSettingEntry_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_UserSettingEntry_descriptor,\n              new java.lang.String[] { \"Scope\", \"Key\", \"Value\", \"UpdateDt\", });\n          internal_static_ModifyUserSettingReq_descriptor =\n            getDescriptor().getMessageTypes().get(51);\n          internal_static_ModifyUserSettingReq_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ModifyUserSettingReq_descriptor,\n              new java.lang.String[] { \"Scope\", \"Key\", \"Value\", });\n          internal_static_Version_descriptor =\n            getDescriptor().getMessageTypes().get(52);\n          internal_static_Version_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_Version_descriptor,\n              new java.lang.String[] { \"Version\", });\n          internal_static_GetUserSettingResult_descriptor =\n            getDescriptor().getMessageTypes().get(53);\n          internal_static_GetUserSettingResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_GetUserSettingResult_descriptor,\n              new java.lang.String[] { \"Entry\", });\n          internal_static_Friend_descriptor =\n            getDescriptor().getMessageTypes().get(54);\n          internal_static_Friend_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_Friend_descriptor,\n              new java.lang.String[] { \"Uid\", \"State\", \"UpdateDt\", \"Alias\", \"Blacked\", \"Extra\", });\n          internal_static_GetFriendsResult_descriptor =\n            getDescriptor().getMessageTypes().get(55);\n          internal_static_GetFriendsResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_GetFriendsResult_descriptor,\n              new java.lang.String[] { \"Entry\", });\n          internal_static_GetFriendRequestResult_descriptor =\n            getDescriptor().getMessageTypes().get(56);\n          internal_static_GetFriendRequestResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_GetFriendRequestResult_descriptor,\n              new java.lang.String[] { \"Entry\", });\n          internal_static_ConnectAckPayload_descriptor =\n            getDescriptor().getMessageTypes().get(57);\n          internal_static_ConnectAckPayload_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ConnectAckPayload_descriptor,\n              new java.lang.String[] { \"MsgHead\", \"FriendHead\", \"FriendRqHead\", \"SettingHead\", \"NodeAddr\", \"NodePort\", \"ServerTime\", });\n          internal_static_IMHttpWrapper_descriptor =\n            getDescriptor().getMessageTypes().get(58);\n          internal_static_IMHttpWrapper_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_IMHttpWrapper_descriptor,\n              new java.lang.String[] { \"Token\", \"ClientId\", \"Request\", \"Data\", });\n          internal_static_SearchUserRequest_descriptor =\n            getDescriptor().getMessageTypes().get(59);\n          internal_static_SearchUserRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_SearchUserRequest_descriptor,\n              new java.lang.String[] { \"Keyword\", \"Fuzzy\", \"Page\", \"DomainId\", \"Type\", });\n          internal_static_SearchUserResult_descriptor =\n            getDescriptor().getMessageTypes().get(60);\n          internal_static_SearchUserResult_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_SearchUserResult_descriptor,\n              new java.lang.String[] { \"Entry\", });\n          internal_static_GetChatroomInfoRequest_descriptor =\n            getDescriptor().getMessageTypes().get(61);\n          internal_static_GetChatroomInfoRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_GetChatroomInfoRequest_descriptor,\n              new java.lang.String[] { \"ChatroomId\", \"UpdateDt\", });\n          internal_static_ChatroomInfo_descriptor =\n            getDescriptor().getMessageTypes().get(62);\n          internal_static_ChatroomInfo_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ChatroomInfo_descriptor,\n              new java.lang.String[] { \"Title\", \"Desc\", \"Portrait\", \"MemberCount\", \"CreateDt\", \"UpdateDt\", \"Extra\", \"State\", });\n          internal_static_GetChatroomMemberInfoRequest_descriptor =\n            getDescriptor().getMessageTypes().get(63);\n          internal_static_GetChatroomMemberInfoRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_GetChatroomMemberInfoRequest_descriptor,\n              new java.lang.String[] { \"ChatroomId\", \"MaxCount\", });\n          internal_static_ChatroomMemberInfo_descriptor =\n            getDescriptor().getMessageTypes().get(64);\n          internal_static_ChatroomMemberInfo_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ChatroomMemberInfo_descriptor,\n              new java.lang.String[] { \"MemberCount\", \"Members\", });\n          internal_static_INT64Buf_descriptor =\n            getDescriptor().getMessageTypes().get(65);\n          internal_static_INT64Buf_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_INT64Buf_descriptor,\n              new java.lang.String[] { \"Id\", });\n          internal_static_NotifyRecallMessage_descriptor =\n            getDescriptor().getMessageTypes().get(66);\n          internal_static_NotifyRecallMessage_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_NotifyRecallMessage_descriptor,\n              new java.lang.String[] { \"Id\", \"FromUser\", });\n          internal_static_BlackUserRequest_descriptor =\n            getDescriptor().getMessageTypes().get(67);\n          internal_static_BlackUserRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_BlackUserRequest_descriptor,\n              new java.lang.String[] { \"Uid\", \"Status\", });\n          internal_static_RouteRequest_descriptor =\n            getDescriptor().getMessageTypes().get(68);\n          internal_static_RouteRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_RouteRequest_descriptor,\n              new java.lang.String[] { \"App\", \"Platform\", \"PushType\", \"DeviceName\", \"DeviceVersion\", \"PhoneName\", \"Language\", \"CarrierName\", \"AppVersion\", \"SdkVersion\", });\n          internal_static_RouteResponse_descriptor =\n            getDescriptor().getMessageTypes().get(69);\n          internal_static_RouteResponse_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_RouteResponse_descriptor,\n              new java.lang.String[] { \"Host\", \"LongPort\", \"ShortPort\", });\n          internal_static_GetTokenRequest_descriptor =\n            getDescriptor().getMessageTypes().get(70);\n          internal_static_GetTokenRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_GetTokenRequest_descriptor,\n              new java.lang.String[] { \"UserId\", \"ClientId\", \"Platform\", });\n          internal_static_LoadRemoteMessages_descriptor =\n            getDescriptor().getMessageTypes().get(71);\n          internal_static_LoadRemoteMessages_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_LoadRemoteMessages_descriptor,\n              new java.lang.String[] { \"Conversation\", \"BeforeUid\", \"Count\", \"ContentType\", });\n          internal_static_MultiCastMessage_descriptor =\n            getDescriptor().getMessageTypes().get(72);\n          internal_static_MultiCastMessage_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_MultiCastMessage_descriptor,\n              new java.lang.String[] { \"FromUser\", \"Content\", \"To\", \"Line\", });\n          internal_static_RecallMultiCastMessageRequest_descriptor =\n            getDescriptor().getMessageTypes().get(73);\n          internal_static_RecallMultiCastMessageRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_RecallMultiCastMessageRequest_descriptor,\n              new java.lang.String[] { \"MessageId\", \"Receiver\", });\n          internal_static_AuthCodeRequest_descriptor =\n            getDescriptor().getMessageTypes().get(74);\n          internal_static_AuthCodeRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_AuthCodeRequest_descriptor,\n              new java.lang.String[] { \"TargetId\", \"Type\", \"Host\", });\n          internal_static_ApplicationConfigRequest_descriptor =\n            getDescriptor().getMessageTypes().get(75);\n          internal_static_ApplicationConfigRequest_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_ApplicationConfigRequest_descriptor,\n              new java.lang.String[] { \"AppId\", \"AppType\", \"Timestamp\", \"Nonce\", \"Signature\", });\n          internal_static_StringPair_descriptor =\n            getDescriptor().getMessageTypes().get(76);\n          internal_static_StringPair_fieldAccessorTable = new\n            com.google.protobuf.GeneratedMessage.FieldAccessorTable(\n              internal_static_StringPair_descriptor,\n              new java.lang.String[] { \"Key\", \"Value\", });\n          return null;\n        }\n      };\n    com.google.protobuf.Descriptors.FileDescriptor\n      .internalBuildGeneratedFileFrom(descriptorData,\n        new com.google.protobuf.Descriptors.FileDescriptor[] {\n        }, assigner);\n  }\n\n  // @@protoc_insertion_point(outer_class_scope)\n}\n"
  },
  {
    "path": "distribution/pom.xml",
    "content": "<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <parent>\n        <relativePath>../</relativePath>\n        <!--<relativePath>../pom.xml</relativePath>-->\n        <artifactId>wildfirechat-parent</artifactId>\n        <groupId>cn.wildfirechat</groupId>\n        <version>1.4.5</version>\n    </parent>\n\n    <artifactId>distribution</artifactId>\n    <packaging>pom</packaging>\n    <name>Moquette - distribution</name>\n\n    <!-- Includes all modules -->\n    <dependencies>\n        <dependency>\n            <groupId>${project.groupId}</groupId>\n            <artifactId>moquette-broker</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n    </dependencies>\n\n\n    <build>\n        <sourceDirectory>${basedir}/src/main/</sourceDirectory> <!-- Force default maven layout -->\n        <plugins>\n            <plugin>\n                <groupId>pl.project13.maven</groupId>\n                <artifactId>git-commit-id-plugin</artifactId>\n                <version>2.1.5</version>\n                <executions>\n                    <execution>\n                        <goals>\n                            <goal>revision</goal>\n                        </goals>\n                    </execution>\n                </executions>\n                <configuration>\n                    <!--日期格式;默认值:dd.MM.yyyy '@' HH:mm:ss z;-->\n                    <dateFormat>yyyyMMddHHmmss</dateFormat>\n                    <!--,构建过程中,是否打印详细信息;默认值:false;-->\n                    <verbose>true</verbose>\n                    <!-- \".git\"文件路径;默认值:${project.basedir}/.git; -->\n                    <dotGitDirectory>${project.basedir}/.git</dotGitDirectory>\n                    <!--若项目打包类型为pom,是否取消构建;默认值:true;-->\n                    <skipPoms>false</skipPoms>\n                    <!--是否生成\"git.properties\"文件;默认值:false;-->\n                    <generateGitPropertiesFile>true</generateGitPropertiesFile>\n                    <!--指定\"git.properties\"文件的存放路径(相对于${project.basedir}的一个路径);-->\n                    <generateGitPropertiesFilename>src/main/resources/git.properties</generateGitPropertiesFilename>\n                    <!--\".git\"文件夹未找到时,构建是否失败;若设置true,则构建失败;若设置false,则跳过执行该目标;默认值:true;-->\n                    <failOnNoGitDirectory>false</failOnNoGitDirectory>\n\n                    <!--git描述配置,可选;由JGit提供实现;-->\n                    <gitDescribe>\n                        <!--是否生成描述属性-->\n                        <skip>false</skip>\n                        <!--提交操作未发现tag时,仅打印提交操作ID,-->\n                        <always>false</always>\n                        <!--提交操作ID显式字符长度,最大值为:40;默认值:7;\n                            0代表特殊意义;后面有解释;\n                        -->\n                        <abbrev>7</abbrev>\n                        <!--构建触发时,代码有修改时(即\"dirty state\"),添加指定后缀;默认值:\"\";-->\n                        <dirty>-dirty</dirty>\n                        <!--always print using the \"tag-commits_from_tag-g_commit_id-maybe_dirty\" format, even if \"on\" a tag.\n                            The distance will always be 0 if you're \"on\" the tag.\n                        -->\n                        <forceLongFormat>false</forceLongFormat>\n                    </gitDescribe>\n                </configuration>\n            </plugin>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <version>2.4</version>\n                <executions>\n                    <execution>\n                        <id>distribution-package</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                        <configuration>\n                            <!-- Specifies the configuration file of the assembly plugin -->\n                            <descriptors>\n                                <descriptor>${basedir}/src/main/assembly/assembly.xml</descriptor>\n                            </descriptors>\n                            <tarLongFileMode>gnu</tarLongFileMode>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n            <plugin>\n                <artifactId>jdeb</artifactId>\n                <groupId>org.vafer</groupId>\n                <version>1.8</version>\n                <executions>\n                    <execution>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>jdeb</goal>\n                        </goals>\n                        <configuration>\n                            <controlDir>${project.basedir}/src/main/deb/control</controlDir>\n                            <skipPOMs>false</skipPOMs>\n                            <deb>${project.build.directory}/im-server-${project.version}.deb</deb>\n                            <dataSet>\n                                <data>\n                                    <src>${project.build.directory}/distribution-${project.version}-bundle-tar.tar.gz</src>\n                                    <type>archive</type>\n                                    <mapper>\n                                        <type>perm</type>\n                                        <prefix>/opt/im-server</prefix>\n                                    </mapper>\n                                </data>\n                                <data>\n                                    <src>${project.basedir}/../systemd/im-server.service</src>\n                                    <type>file</type>\n                                    <mapper>\n                                        <type>perm</type>\n                                        <prefix>/usr/lib/systemd/system</prefix>\n                                    </mapper>\n                                </data>\n                            </dataSet>\n                        </configuration>\n                    </execution>\n                </executions>\n            </plugin>\n\n<!--        打包RPM 包需要本地有rpm命令才可以，linux和mac都可以安装rpm。如果是windows需要cygwin安装rpm才可以，如果不需要rpm包，可以把这个plugin注释掉-->\n<!--        打包RPM插件，如果需要打包RPM格式请打开下面注释  -->\n<!--            <plugin>-->\n<!--                <groupId>org.codehaus.mojo</groupId>-->\n<!--                <artifactId>rpm-maven-plugin</artifactId>-->\n<!--                <version>2.2.0</version>-->\n<!--                <executions>-->\n<!--                    <execution>-->\n<!--                        <id>generate-rpm</id>-->\n<!--                        <goals>-->\n<!--                            <goal>rpm</goal>-->\n<!--                        </goals>-->\n<!--                    </execution>-->\n<!--                </executions>-->\n<!--                <configuration>-->\n<!--                    <group>Applications/Chat</group>-->\n<!--                    <name>im-server</name>-->\n<!--                    <needarch>noarch</needarch>-->\n<!--                    <targetOS>linux</targetOS>-->\n<!--                    <prefix>/opt/im-server</prefix>-->\n<!--                    <defineStatements>-->\n<!--                        <defineStatement>_unpackaged_files_terminate_build 0</defineStatement>-->\n<!--                    </defineStatements>-->\n<!--                    <copyTo>-->\n<!--                        target/im-server-${project.version}.rpm-->\n<!--                    </copyTo>-->\n<!--                    <requires>-->\n<!--                        <require>java-1.8.0-openjdk-headless</require>-->\n<!--                    </requires>-->\n<!--                    <mappings>-->\n<!--                        <mapping>-->\n<!--                            <directory>/opt/im-server</directory>-->\n<!--                            <filemode>755</filemode>-->\n<!--                            <sources>-->\n<!--                                <source>-->\n<!--                                    <location>${project.build.directory}/distribution-${project.version}-bundle-tar.tar.gz</location>-->\n<!--                                </source>-->\n<!--                            </sources>-->\n<!--                        </mapping>-->\n<!--                        <mapping>-->\n<!--                            <directory>/usr/lib/systemd/system</directory>-->\n<!--                            <filemode>644</filemode>-->\n<!--                            <username>root</username>-->\n<!--                            <groupname>root</groupname>-->\n<!--                            <directoryIncluded>false</directoryIncluded>-->\n<!--                            <sources>-->\n<!--                                <source>-->\n<!--                                    <location>${project.basedir}/../systemd/im-server.service</location>-->\n<!--                                </source>-->\n<!--                            </sources>-->\n<!--                        </mapping>-->\n<!--                    </mappings>-->\n<!--                    <postinstallScriptlet>-->\n<!--                        <scriptFile>${project.basedir}/src/main/rpm/install.sh</scriptFile>-->\n<!--                        <fileEncoding>utf-8</fileEncoding>-->\n<!--                        <filter>true</filter>-->\n<!--                    </postinstallScriptlet>-->\n<!--                    <postremoveScriptlet>-->\n<!--                        <scriptFile>${project.basedir}/src/main/rpm/uninstall.sh</scriptFile>-->\n<!--                        <fileEncoding>utf-8</fileEncoding>-->\n<!--                        <filter>true</filter>-->\n<!--                    </postremoveScriptlet>-->\n<!--                </configuration>-->\n<!--            </plugin>-->\n<!--            打包RPM 结束-->\n\n        </plugins>\n    </build>\n</project>    \n"
  },
  {
    "path": "distribution/src/main/assembly/assembly.xml",
    "content": "<assembly xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n          xmlns=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2\"\n          xsi:schemaLocation=\"http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd\">\n    <id>bundle-tar</id>\n    <formats>\n        <format>tar.gz</format>\n        <!--<format>dir</format>-->\n    </formats>\n    <includeBaseDirectory>false\n    </includeBaseDirectory> <!-- disable the creation of root's distribution dir in the archive -->\n\n    <fileSets>\n        <fileSet>\n            <directory>../broker/migrate/mysql/</directory>\n            <outputDirectory>/migrate/mysql</outputDirectory>\n        </fileSet>\n\n        <fileSet>\n            <directory>../broker/migrate/h2/</directory>\n            <outputDirectory>/migrate/h2</outputDirectory>\n        </fileSet>\n\n        <fileSet>\n            <directory>src/main/resources/</directory>\n            <outputDirectory>config/</outputDirectory>\n        </fileSet>\n\n        <fileSet>\n            <directory>../systemd/</directory>\n            <outputDirectory>/systemd</outputDirectory>\n        </fileSet>\n\n        <fileSet>\n            <directory>src/main/checker/</directory>\n            <outputDirectory>checker/</outputDirectory>\n        </fileSet>\n    </fileSets>\n\n    <files>\n        <!-- executables scripts-->\n        <file>\n            <source>src/main/scripts/wildfirechat.sh</source>\n            <outputDirectory>bin</outputDirectory>\n            <fileMode>0755</fileMode>\n        </file>\n\n        <file>\n            <source>src/main/scripts/stop.sh</source>\n            <outputDirectory>bin</outputDirectory>\n            <fileMode>0755</fileMode>\n        </file>\n\n        <file>\n            <source>src/main/scripts/wildfirechat.bat</source>\n            <outputDirectory>bin</outputDirectory>\n        </file>\n\n        <file>\n            <source>src/main/files/README.txt</source>\n        </file>\n\n        <file>\n            <source>../release_note.md</source>\n        </file>\n\n        <file>\n            <source>../broker/target/moquette-broker-${project.version}.jar</source>\n            <outputDirectory>lib/</outputDirectory>\n            <destName>moquette-broker-${project.version}.jar</destName>\n        </file>\n\n        <file>\n            <source>../sdk/target/sdk-${project.version}.jar</source>\n            <outputDirectory>server_sdk/</outputDirectory>\n            <destName>sdk-${project.version}.jar</destName>\n        </file>\n\n        <file>\n            <source>../sdk/sdk_readme.txt</source>\n            <outputDirectory>server_sdk/</outputDirectory>\n            <destName>sdk_readme.txt</destName>\n        </file>\n\n        <file>\n            <source>../common/target/common-${project.version}.jar</source>\n            <outputDirectory>server_sdk/</outputDirectory>\n            <destName>common-${project.version}.jar</destName>\n        </file>\n\n        <file>\n            <source>../sdk/target/checker.jar</source>\n            <outputDirectory>checker/</outputDirectory>\n        </file>\n\n        <file>\n            <source>../docker/Dockerfile</source>\n            <outputDirectory>docker/</outputDirectory>\n        </file>\n\n        <file>\n            <source>../docker/README.md</source>\n            <outputDirectory>docker/</outputDirectory>\n        </file>\n    </files>\n\n    <dependencySets>\n        <dependencySet>\n            <outputDirectory>lib/</outputDirectory>\n            <useProjectArtifact>true</useProjectArtifact> <!-- avoid inclusion of the artifact itself -->\n            <excludes>\n                <exclude>io.moquette:moquette-broker</exclude>\n            </excludes>\n        </dependencySet>\n    </dependencySets>\n</assembly>\n"
  },
  {
    "path": "distribution/src/main/checker/README.md",
    "content": "部署IM服务后，可以使用Server SDK通过API来检查服务的部署情况，可以执行:\n```shell\njava -jar checker.jar http://127.0.0.1:18080 123456 http://127.0.0.1 false false\n```\n来检查。检查之后会产生垃圾数据，请在检查之后停掉IM服务后，再删除掉IM服务数据库。此检查仅检查API，检查通过并不代表部署肯定成功，还需要客户端来验证。\n"
  },
  {
    "path": "distribution/src/main/deb/control/control",
    "content": "Package: im-server\nVersion: [[version]]\nSection: misc\nPriority: optional\nArchitecture: all\nMaintainer: Wildfirechat <support@wildfirechat.cn>\nDescription:  IM Server\nDistribution: development\nDepends: openjdk-8-jre-headless\nHomepage: https://wildfirechat.cn\n"
  },
  {
    "path": "distribution/src/main/deb/control/postinst",
    "content": "set -e\nsed -i 's/h2db.path .\\/h2db\\/wfchat/h2db.path \\/var\\/lib\\/im-server\\/h2db\\/imdb/' /opt/im-server/config/wildfirechat.conf\nsed -i 's/local.media.storage.root .\\/media/local.media.storage.root \\/var\\/lib\\/im-server\\/media/' /opt/im-server/config/wildfirechat.conf\nsed -i 's/<Property name=\"MSG_LOG_HOME\">.\\/logs<\\/Property>/<Property name=\"MSG_LOG_HOME\">\\/var\\/log\\/im-server<\\/Property>/' /opt/im-server/config/log4j2.xml\nsed -i 's/WILDFIRECHAT_CONFIG_PATH=$WILDFIRECHAT_HOME/WILDFIRECHAT_CONFIG_PATH=\\/etc\\/im-server/' /opt/im-server/bin/wildfirechat.sh\n\nif [ ! -d /etc/im-server ]; then\nmkdir /etc/im-server\nfi\n\nif [ ! -d /var/log/im-server ]; then\nmkdir /var/log/im-server\nfi\n\nmv -f  /opt/im-server/config /etc/im-server\nsystemctl daemon-reload\n\necho \"IM server folders:\"\necho \"/etc/im-server/config     config\"\necho \"/opt/im-server            binary files\"\necho \"/var/log/im-server        logs\"\necho \"/var/lib/im-server/h2db   embed db\"\necho \"/var/lib/im-server/media  embed media files\"\n"
  },
  {
    "path": "distribution/src/main/deb/control/postrm",
    "content": "set -e\nrm -rf /opt/im-server\nrm -rf /etc/im-server\nrm -rf /var/log/im-server\nrm -rf /usr/lib/systemd/system/im-server.service\n\nif [ -d /var/lib/im-server/h2db ]; then\necho \"IM embed db file not deleted in path /var/lib/im-server/h2db, if you don't need it anymore, please remove it manually\"\nfi\n\nif [ -d /var/lib/im-server/media ]; then\necho \"IM embed media files not deleted in path /var/lib/im-server/media, if you don't need it anymore, please remove it manually\"\nfi\n\nsystemctl daemon-reload\n\n"
  },
  {
    "path": "distribution/src/main/files/README.txt",
    "content": "部署方法请参考野火IM开发文档 http://docs.wildfirechat.cn\n"
  },
  {
    "path": "distribution/src/main/resources/c3p0-config.xml",
    "content": "<?xml version =\"1.0\" encoding=\"UTF-8\"?>\n<c3p0-config>\n    <!-- This is default config! -->\n    <default-config>\n        <property name=\"initialPoolSize\">10</property>\n        <property name=\"maxIdleTime\">30</property>\n        <property name=\"maxPoolSize\">100</property>\n        <property name=\"minPoolSize\">10</property>\n        <property name=\"maxStatements\">200</property>\n    </default-config>\n\n    <!-- This is my config for mysql-->\n    <named-config name=\"mysql\">\n        <!-- 指定数据库连接源的基本属性 -->\n        <!--MySQL数据库驱动程序-->\n        <property name=\"driverClass\">com.mysql.cj.jdbc.Driver</property>\n        <!--MySQL数据库地址-->\n        <property name=\"jdbcUrl\">jdbc:mysql://localhost:3306/wfchat?useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true&amp;useUnicode=true&amp;characterEncoding=UTF-8</property>\n        <!--MySQL数据库用户名-->\n        <property name=\"user\">root</property>\n        <!--MySQL数据库密码-->\n        <property name=\"password\">123456</property>\n        <!-- 初始化连接池中的连接数，取值应在minPoolSize与maxPoolSize之间，默认为3-->\n        <property name=\"initialPoolSize\">10</property>\n        <!--最大空闲时间，60秒内未使用则连接被丢弃。若为0则永不丢弃。默认值: 0 -->\n        <property name=\"maxIdleTime\">30</property>\n        <!--连接池中保留的最大连接数。默认值: 15 -->\n        <property name=\"maxPoolSize\">100</property>\n        <!-- 连接池中保留的最小连接数，默认为：3-->\n        <property name=\"minPoolSize\">10</property>\n        <!--c3p0全局的PreparedStatements缓存的大小。如果maxStatements与maxStatementsPerConnection均为0，则缓存不生效，只要有一个不为0，则语句的缓存就能生效。如果默认值: 0-->\n        <property name=\"maxStatements\">200</property>\n        <!-- 当连接池连接耗尽时，客户端调用getConnection()后等待获取新连接的时间，超时后将抛出SQLException，如设为0则无限期等待。单位毫秒。默认: 0 -->\n        <property name=\"checkoutTimeout\">3000</property>\n        <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。默认值: 3 -->\n        <property name=\"acquireIncrement\">2</property>\n        <!--定义在从数据库获取新连接失败后重复尝试的次数。默认值: 30 ；小于等于0表示无限次-->\n        <property name=\"acquireRetryAttempts\">0</property>\n        <!--重新尝试的时间间隔，默认为：1000毫秒-->\n        <property name=\"acquireRetryDelay\">1000</property>\n        <!--关闭连接时，是否提交未提交的事务，默认为false，即关闭连接，回滚未提交的事务 -->\n        <property name=\"autoCommitOnClose\">false</property>\n        <!--c3p0将建一张名为Test的空表，并使用其自带的查询语句进行测试。如果定义了这个参数那么属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作，它将只供c3p0测试使用。默认值: null -->\n<!--        <property name=\"automaticTestTable\">Test</property>-->\n        <!--如果为false，则获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常，但是数据源仍有效保留，并在下次调用getConnection()的时候继续尝试获取连接。如果设为true，那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。默认: false-->\n        <property name=\"breakAfterAcquireFailure\">false</property>\n        <!--每60秒检查所有连接池中的空闲连接。默认值: 0，不检查 -->\n        <property name=\"idleConnectionTestPeriod\">60</property>\n        <!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。默认值: 0 -->\n        <!--<property name=\"maxStatementsPerConnection\"></property>-->\n    </named-config>\n\n\n    <!-- This is my config for oracle -->\n    <named-config name=\"oracle\">\n        <property name=\"driverClass\">oracle.jdbc.driver.OracleDriver</property>\n        <property name=\"jdbcUrl\">jdbc:oracle:thin:@localhost:1521:orcl</property>\n        <property name=\"user\">scott</property>\n        <property name=\"password\">liang</property>\n        <property name=\"initialPoolSize\">10</property>\n        <property name=\"maxIdleTime\">30</property>\n        <property name=\"maxPoolSize\">100</property>\n        <property name=\"minPoolSize\">10</property>\n        <property name=\"maxStatements\">200</property>\n    </named-config>\n</c3p0-config>\n"
  },
  {
    "path": "distribution/src/main/resources/hazelcast.xml",
    "content": "<hazelcast\n        xsi:schemaLocation=\"http://www.hazelcast.com/schema/config\n  http://www.hazelcast.com/schema/config/hazelcast-config-3.5.xsd\"\n        xmlns=\"http://www.hazelcast.com/schema/config\"\n        xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n    <network>\n        <join>\n            <multicast enabled=\"false\"/>\n        </join>\n    </network>\n\n    <properties>\n        <property name=\"hazelcast.logging.type\">slf4j</property>\n    </properties>\n\n    <!-- map eviction -->\n    <!-- http://docs.hazelcast.org/docs/latest-development/manual/html/Distributed_Data_Structures/Map/Map_Eviction.html -->\n    <map name=\"messages_map\">\n        <!-- 7 days -->\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.MessageLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <map name=\"groups_map\">\n        <!-- 7 days -->\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.GroupLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <map name=\"users\">\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.UserLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <map name=\"user_status\">\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.UserStatusLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <map name=\"user_friends_empty\">\n        <time-to-live-seconds>86400</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n    </map>\n\n    <set name=\"node_ids\"/>\n\n    <multimap name=\"user_setting\">\n    </multimap>\n\n    <multimap name=\"group_members\">\n    </multimap>\n\n    <map name=\"chatrooms\">\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.ChatroomLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <map name=\"user_chatroom\">\n    </map>\n\n    <multimap name=\"chatroom_black\">\n    </multimap>\n\n    <multimap name=\"chatroom_manager\">\n    </multimap>\n\n    <map name=\"robots\">\n        <!-- 7 days -->\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.RobotLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <map name=\"devices\">\n        <!-- 7 days -->\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.DeviceLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n\n    <multimap name=\"user_robots\">\n    </multimap>\n\n    <multimap name=\"user_devices\">\n    </multimap>\n\n\n    <multimap name=\"chatroom_members\">\n    </multimap>\n\n    <multimap name=\"user_friends\">\n    </multimap>\n\n    <multimap name=\"user_friends_request\">\n    </multimap>\n\n    <map name=\"channels_map\">\n        <!-- 7 days -->\n        <time-to-live-seconds>604800</time-to-live-seconds>\n        <eviction-policy>LRU</eviction-policy>\n        <max-size policy=\"PER_NODE\">1000000</max-size>\n        <eviction-percentage>10</eviction-percentage>\n        <map-store enabled=\"true\">\n            <class-name>io.moquette.persistence.ChannelLoader</class-name>\n            <write-delay-seconds>0</write-delay-seconds>\n        </map-store>\n    </map>\n\n    <multimap name=\"channel_listeners\">\n    </multimap>\n\n</hazelcast>\n"
  },
  {
    "path": "distribution/src/main/resources/log4j2.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->\n<!--status=\"WARN\" :用于设置log4j2自身内部日志的信息输出级别，默认是OFF-->\n<!--monitorInterval=\"30\"  :间隔秒数,自动检测配置文件的变更和重新配置本身-->\n<configuration status=\"WARN\" monitorInterval=\"60\">\n    <Properties>\n        <!--        日志路径-->\n        <Property name=\"MSG_LOG_HOME\">./logs</Property>\n<!--        <Property name=\"MSG_LOG_HOME\">/var/log/wildfirechat/im/logs</Property>-->\n        <property name=\"charset\">UTF-8</property>\n        <property name=\"pattern\">%d %-5p [%t] %C{2} (%F:%L) - %m%n</property>\n    </Properties>\n    <!--appenders:定义输出内容,输出格式,输出方式,日志保存策略等,常用其下三种标签[console,File,RollingFile]-->\n    <appenders>\n        <!--console :控制台输出的配置-->\n        <console name=\"Console\" target=\"SYSTEM_OUT\">\n            <!--PatternLayout :输出日志的格式,LOG4J2定义了输出代码,详见第二部分-->\n            <PatternLayout pattern=\"[%d{HH:mm:ss:SSS}] [%p] - %l - %m%n\"/>\n        </console>\n\n        <RollingRandomAccessFile name=\"RollingFileInfo\" immediateFlush=\"false\"\n                                 fileName=\"${MSG_LOG_HOME}/wildfirechat.log\"\n                                 filePattern=\"${MSG_LOG_HOME}/backup/wildfirechat.%d{yyyyMMddHHmm}.zip\">\n            <Filters>\n                <ThresholdFilter level=\"INFO\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n            </Filters>\n            <PatternLayout pattern=\"${pattern}\" />\n            <Policies>\n                <!-- TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件,interval=\"6\" : 自定义文件滚动时间间隔,每隔6小时产生新文件, modulate=\"true\" : 产生文件是否以0点偏移时间,即6点,12点,18点,0点-->\n                <TimeBasedTriggeringPolicy interval=\"6\" modulate=\"true\"/>\n                <!-- SizeBasedTriggeringPolicy :文件大小滚动策略-->\n                <SizeBasedTriggeringPolicy size=\"100 MB\"/>\n            </Policies>\n\n            <DefaultRolloverStrategy max=\"24\">\n                <Delete basePath=\"${MSG_LOG_HOME}\" maxDepth=\"2\">\n                    <IfFileName glob=\"*/wildfirechat.*.zip\" />\n                    <IfLastModified age=\"24H\" />\n                </Delete>\n            </DefaultRolloverStrategy>\n        </RollingRandomAccessFile>\n\n        <RollingRandomAccessFile name=\"RollingFileWarn\" immediateFlush=\"true\"\n                                 fileName=\"${MSG_LOG_HOME}/wildfirechat_warn.log\"\n                                 filePattern=\"${MSG_LOG_HOME}/backup/wildfirechat_warn.%d{yyyyMMddHH}.zip\">\n            <Filters>\n                <ThresholdFilter level=\"WARN\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n            </Filters>\n            <PatternLayout pattern=\"${pattern}\" />\n            <Policies>\n                <!-- TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件,interval=\"6\" : 自定义文件滚动时间间隔,每隔6小时产生新文件, modulate=\"true\" : 产生文件是否以0点偏移时间,即6点,12点,18点,0点-->\n                <TimeBasedTriggeringPolicy interval=\"6\" modulate=\"true\"/>\n                <!-- SizeBasedTriggeringPolicy :文件大小滚动策略-->\n                <SizeBasedTriggeringPolicy size=\"100 MB\"/>\n            </Policies>\n\n            <DefaultRolloverStrategy max=\"24\">\n                <Delete basePath=\"${MSG_LOG_HOME}\" maxDepth=\"2\">\n                    <IfFileName glob=\"*/wildfirechat_warn.*.zip\" />\n                    <IfLastModified age=\"24H\" />\n                </Delete>\n            </DefaultRolloverStrategy>\n        </RollingRandomAccessFile>\n\n        <RollingRandomAccessFile name=\"RollingFileError\" immediateFlush=\"true\"\n                                 fileName=\"${MSG_LOG_HOME}/wildfirechat_error.log\"\n                                 filePattern=\"${MSG_LOG_HOME}/backup/wildfirechat_error.%d{yyyyMMddHH}.zip\">\n            <Filters>\n                <ThresholdFilter level=\"ERROR\" onMatch=\"ACCEPT\" onMismatch=\"DENY\"/>\n            </Filters>\n            <PatternLayout pattern=\"${pattern}\" />\n            <Policies>\n                <!-- TimeBasedTriggeringPolicy :时间滚动策略,默认0点小时产生新的文件,interval=\"6\" : 自定义文件滚动时间间隔,每隔6小时产生新文件, modulate=\"true\" : 产生文件是否以0点偏移时间,即6点,12点,18点,0点-->\n                <TimeBasedTriggeringPolicy interval=\"6\" modulate=\"true\"/>\n                <!-- SizeBasedTriggeringPolicy :文件大小滚动策略-->\n                <SizeBasedTriggeringPolicy size=\"100 MB\"/>\n            </Policies>\n\n            <DefaultRolloverStrategy max=\"24\">\n                <Delete basePath=\"${MSG_LOG_HOME}\" maxDepth=\"2\">\n                    <IfFileName glob=\"*/wildfirechat_error.*.zip\" />\n                    <IfLastModified age=\"24H\" />\n                </Delete>\n            </DefaultRolloverStrategy>\n        </RollingRandomAccessFile>\n    </appenders>\n\n    <!--然后定义logger，只有定义了logger并引入的appender，appender才会生效-->\n    <loggers>\n        <!--过滤掉spring和mybatis的一些无用的DEBUG信息-->\n        <!--Logger节点用来单独指定日志的形式，name为包路径,比如要为org.springframework包下所有日志指定为INFO级别等。 -->\n        <!--        <logger name=\"org.springframework\" level=\"INFO\"></logger>-->\n        <!--        <logger name=\"org.mybatis\" level=\"INFO\"></logger>-->\n        <!-- Root节点用来指定项目的根日志，如果没有单独指定Logger，那么就会默认使用该Root日志输出 -->\n        <root level=\"INFO\">\n            <!--            <appender-ref ref=\"Console\"/>-->\n            <appender-ref ref=\"RollingFileInfo\"/>\n            <appender-ref ref=\"RollingFileWarn\"/>\n            <appender-ref ref=\"RollingFileError\"/>\n        </root>\n        <!--AsyncLogger :异步日志,LOG4J有三种日志模式,全异步日志,混合模式,同步日志,性能从高到底,线程越多效率越高,也可以避免日志卡死线程情况发生-->\n        <!--additivity=\"false\" : additivity设置事件是否在root logger输出，为了避免重复输出，可以在Logger 标签下设置additivity为”false”-->\n        <AsyncLogger name=\"AsyncLogger\" level=\"trace\" includeLocation=\"true\" additivity=\"false\">\n            <appender-ref ref=\"RollingFileInfo\"/>\n        </AsyncLogger>\n    </loggers>\n</configuration>\n"
  },
  {
    "path": "distribution/src/main/resources/wildfirechat.conf",
    "content": "## 注意事项：\n#1. 配置文件修改是不能直接生效的，需要重启后才能生效。\n#2. Linux下使用windows格式配置文件会出错，包括本文件，c3p0文件，hz配置。常见于在windows系统上修改，然后上传到linux服务器，可以在linux服务器上直接修改或者上传到linux服务器后转换成unix格式，具体转换方法请百度。\n\n#*********************************************************************\n# Server configuration\n#*********************************************************************\n#服务器的接入IP。给客户端提供是${server.ip}和${http_port}。\n#客户端会从${http_port}端口获取到长链接端口。这个地址一定要改成客户端可以访问到的IP地址\n#（如果您部署云服务器上或者具有独立公网出口的服务器上，请改为对应的公网IP；如果您部署在在内网环境下，在内网使用，这个地方改成内网地址）\nserver.ip 0.0.0.0\n\n##原生客户端长链接端口。如果使用4层的反向代理或者类似组件，需要设置长链接保持时间为10分钟。不支持7层代理。\nport 1883\n\n##客户端短链接端口，客户端固定使用80端口不能修改。\n##如果是国企事业单位等因为政策原因无法使用80端口，可以联系野火解决。\nhttp_port 80\n\n#管理端口\nhttp.admin.port 18080\n\n##节点ID，当集群部署时，一定不能有重复。\nnode_id 1\n\n##绑定IP，不要打开，除非有特殊需求才可以打开\n#host 0.0.0.0\n\n##本地绑定端口\nlocal_port 80\n\n## 是否使用内置DB。0使用mysql；1使用h2db。\n## MySQL需要把事物隔离级别改成\"Read committed\"，使用命令来修改\"set global transaction_isolation='read-committed';\"，其他数据库默认已经是这个级别不用修改\n## 如果使用MySQL，请在c3p0.xml文件中配置JDBC信息。\n## 如果是MySQL5.7，需要开启长索引的支持，在数据库中执行命令:\"set global innodb_large_prefix=on;\"。其他版本默认支持，不用修改。\n## 如果使用MySQL 8.0.30以上版本，有个特性是创建表时如果没有主键将会自动创建一个主键\"my_key_id\"，如果此功能打开，在执行mysql脚本V19__add_id_for_sensitive_word.sql时将会报错，提示不能2个主键。\n## 解决办法就是运行出错后删除掉系统自动创建的主键\"my_key_id\"，然后继续执行。\nembed.db 1\n\n## 是否自动清理历史消息记录，当为true时，IM服务会定时扫描t_messages_x和t_user_messages_x表，清除掉3年前的历史消息。\n## 如果不开启自动清理，需要手动清理t_messages_x和t_user_messages_x表内的历史数据，保存数据不能超过3年。\n## 如果需要消息保存更长时间，可以把临近销毁的消息转储到别的数据库，客户端在拉取不到服务器消息时，再去转储的数据库拉取。\n## 使用mongodb时次开关无效（因为mongodb设置了消息过期时间，会自动清理，仅专业版支持mongodb）。\ndb.auto_clean_history_messages true\n\n## h2db数据库的路径，默认为程序目录下的，可以指定其他目录。如果使用MySQL，可以忽略此配置\nh2db.path ./h2db/wfchat\n\n##服务器管理接口密钥。如果修改此端口需要同步修改使用管理API的地方，比如应用服务。\nhttp.admin.secret_key 123456\n\n##服务器API接口参数是否检查时间。当设置为false时，所有的请求会检查时间的有效性；当设置为true时，可以在http.admin.secret_key保持不变的情况下，使用固定的服务API签名\n##nonce = \"76616\", timestamp = \"1558350862502\", sign = \"b98f9b0717f59febccf1440067a7f50d9b31bdde\"\nhttp.admin.no_check_time false\n\n##用来生产im token的私钥，只在服务器使用，客户端不用。正式使用时为了安全一定要修改这个值，切记切记\ntoken.key testim\n\n##token的过期时间，单位为毫秒，默认为无限期。如果需要设置无限期，客户端上一定需要加上token过期的处理。token过期的处理请参考文档的常见问题\n##token.expire_time 2592000000\n\n##客户端（目前只有android）的应用签名（一个应用最取第一个签名），如果有多个签名(多个客户端)，用英文逗号分开。获取签名方法请参考文档：https://docs.wildfirechat.cn/blogs/签名验证.html\n#connect.client_signature_list eNkezQ1g9OsnhfLSFUY1vzKDzhs=,xykezQ1g9OsnhfLSFUY1vzKDzhs=\n\n##是否拒绝空签名的android客户端， 默认为true。当有旧的客户端需要兼容时改成false，当所有都是新客户端时，改成true。\n#connect.reject_empty_signature true\n\n##是否使用AES256加密。默认客户端和服务器都是AES128加密，如果需要开启AES256，需要客户端和IM服务同时开通。\n#encrypt.use_aes256 true\n\n##当创建一个对象时（用户，群组，频道，机器人等），如果没有传入ID，野火会为这个对象生成一个ID。如果id.use_uuid为true，会使用uuid作为对象ID，否则会使用野火短ID，默认为false。\n## 短ID有个很大的风险是容易被人穷举进行攻击。建议用UUID。\nid.use_uuid true\n\n##首次登录，是否接收之前的历史消息。\n##0 不接收历史消息，只接收${message.compensate_time_limit}毫秒以内的消息，由于服务器没有保存已经收取记录，所以如果有超过${message.compensate_time_limit}毫秒之前未收取的消息也不会收取下拉；\n##1接收，会接收 message.max_queue 配置的条数的历史消息\nmessage.roaming 0\n\n## 消息补偿时限，当${message.roaming}为0时，会同步时限以内且小于${message.max_queue}的消息，默认时限为5分钟。当${message.roaming}为1时，会接收 message.max_queue 配置的条数的历史消息。\nmessage.compensate_time_limit 300000\n\n##是否开启拉取远程历史消息。如果为1，客户端在会话内如果本地消息读取完了，可以下拉继续加载在服务器上的该会话的消息；如果为0则不能。\nmessage.remote_history_message 0\n\n##服务器为每个用户缓存的消息数量。这个值改得太大，拉取消息时间变长，另外会占用大量内存。\nmessage.max_queue 1024\n\n##是否开启拉取聊天室远程历史消息。如果为1，可以下拉继续加载在服务器上的该聊天室的消息；如果为0则不能。默认为1\nmessage.chatroom_remote_history_message 1\n\n##是否禁止陌生人聊天\nmessage.disable_stranger_chat false\n\n##当禁止陌生人聊天时，允许聊天的用户id，比如管理员或者文件传输助手等。用户id以英文逗号分割。\nmessage.allow_stranger_chat_list admin,FireRobot,wfc_file_transfer\n\n##当禁止陌生人聊天时，允许聊天的线路。\n#message.allow_stranger_line 100,101\n\n##黑名单策略，0 发送失败，返回被拉黑的错误码；1 发送成功但消息被服务器直接丢弃\nmessage.blacklist.strategy 0\n\n##是否禁止服务器端消息搜索，该功能暂未实现。目前的影响是如果打开，则存储消息时不单独保存_searchable_content字段\nmessage.disable_remote_search  false\n\n##是否数据库中加密消息内容。注意这个开关在服务运行起来后不能改变了，避免读取数据库时无法恢复历史消息。\n##如果要避免数据库中明文存储消息内容，请打开这个开关和message.disable_remote_search开关\nmessage.encrypt_message_content  false\n\n##允许客户端撤回用户自己发送的消息时限，单位是秒。0是不允许撤回；-1是无限制撤回。\n##Server API不受此限制，可以撤回任意时限内的消息\n##群组管理员或群主撤回群成员消息不受此限制，可以撤回任意时限内的消息。但管理员或群主撤回自己的消息还是需要准守此时间限制。\n##修改此参数需要同步修改客户端UI，客户端UI代码有判断撤回是否显示的逻辑。\nmessage.recall_time_limit 120\n\n##禁止群主/群管理员撤回群内消息，关闭时群主/群管理员可以撤回任意时间段内群内成员的消息。\nmessage.disable_group_manager_recall false\n\n##禁止客户端发送消息类型，消息类型以逗号分开，下面3个值为示例，可以删除。\n##一般用于重要类型消息，比如交易、充值等，禁止客户端发送，仅限于服务器发送，提高安全性。\n#message.forbidden_client_send_types 3999,4000,4001\n\n## 当禁止发送消息时，允许例外发送的消息。这种一般用户需要被动回应的消息。比如群中被禁言的用户，他无法主动发起音视频，但可以接听未被禁言用户的音视频\n## 因为音视频使用了消息作为信令，所以就需要允许发送音视频信令。如果开发了其它场景也需要被动回应消息，可以加在这里。\n## 黑名单时允许发送的消息类型\nmessage.blacklist_exception_types 401,402,403,404,405,407,408,410,411\n## 群禁言或者聊天室或者频道禁言时允许发送的消息类型\nmessage.group_mute_exception_types 401,402,403,404,405,407,408,410,411\n## 用户被全局禁言时允许发送的消息类型\nmessage.global_mute_exception_types 401,402,403,404,405,407,408,410,411\n\n## 离线用户推送过期天数，0是永不过期，建议配置为7天。\nmessage.push_expired_days 7\n\n## 当会话静音/全局静音/PC在线静音时，普通消息都不会有推送，如果有某些消息类型需要此时保持推送，可以配置到这里。此配置对消息免打扰时段无效。\n## 此配置只影响远程推送，需要客户端处理客户端在线且在后台收到此消息的处理，需要针对这些消息类型加上本地通知。\n## 强制推送消息的MessagePayload中pushContent和pushData至少要存在一个才可以推送。\n## 消息类型以英文逗号分割。\n#message.force_push_types 401,402\n\n## 群发消息(包括server api群发和全局频道群发)时，目标用户是否来自于t_user表。如果使用野火托管用户信息，请设置为true，否则设置为false。\nmessage.broadcast.target_from_user_table true\n\n## 消息转发功能开启时，开关是否不转发server api接口消息。\n## 当为true时，不转发server api发送的消息；当为false时，转发server api发送的消息。\nmessage.no_forward_admin_message false\n\n## 消息转发功能开启时，转发信息是否带上用户clientId和平台类型。\nmessage.forward_with_client_info false\n\n## 消息转发功能开启时，转发信息是否带上发送者的用户信息\nmessage.forward_with_sender_info false\n\n## 消息转发功能开启时，转发信息是否带上目标的信息，单聊时是对方用户信息，群聊时是群组信息，频道时是频道信息\nmessage.forward_with_target_info false\n\n## 允许发送单聊消息给被封禁用户\nmessage.allow_send_to_forbidden_user false\n\n## 机器人回调信息是否带上用户clientId和平台类型。\nrobot.callback_with_client_info false\n\n## 机器人回调信息是否带上发送者的用户信息\nrobot.callback_with_sender_info false\n\n## 机器人回调信息是否带上目标的信息，单聊时是对方用户信息，群聊时是群组信息，频道时是频道信息\nrobot.callback_with_target_info false\n\n## 是否允许@会话外的机器人。如果为true，单聊或者群聊时，可以@不在会话中的机器人。当机器人收到消息后，可以回复消息。\n## 如果为false，不能@不在会话中的机器人。机器人不在会话中时，也不能回复消息。\nrobot.mention_external_robot true\n\n## 机器人获取信息允许的字段，可以获取userId/displayName/portrait，其他需要这里配置允许。\n## 第一位(1)是name， 第二位(2)是mobile，第三(4)位是email，第四位(8)是address，第五位(16)是company，第六位(32)是extra，\n## 第七位(64)是updateDt，第八位(128)是gender，第九位(256)是social，第十位(512)是type。\n## 比如允许获取name和email就是5(1+4)，允许获取name和mobile和company和type就是531（1+2+16+512），允许全部是1023(1+2+...+512)\n#robot.get_user_info_mask 1023\n\n## 频道回调信息是否带上用户clientId和平台类型。\nchannel.callback_with_client_info false\n\n## 频道回调信息是否带上发送者的用户信息。\nchannel.callback_with_sender_info false\n\n## 频道回调信息是否带上频道信息\nchannel.callback_with_target_info false\n\n## 频道回调新方式，在新方式下，如果有callback地址就会总是回调客户端发送的消息（包括owner和订阅者）。automatic属性控制订阅者发送的消息是否发给owner， 0发，1不发。\n## 旧的方式是，automatic为0时，订阅者的消息发给owner，不转发消息到callback地址。为1时，把订阅者的消息转发给callback地址，不发给owner。\nchannel.new_callback_feature true\n\n##禁止搜索用户\nfriend.disable_search false\n\n##禁止按照昵称搜索用户。\nfriend.disable_nick_name_search false\n\n##禁止按照用户id搜索用户，默认为false。\nfriend.disable_user_id_search false\n\n##禁止发送好友邀请，通过server api添加好友不受此限制(force参数需要为true)\nfriend.disable_friend_request false\n\n##好友请求重复发送的间隔，单位是毫秒，默认是7天，0为无限长期限。\nfriend.repeat_request_duration 604800000\n\n##好友请求被拒绝后再次发送的间隔，单位是毫秒，默认是30天，0为不限制。不能小于friend.repeat_request_duration。\nfriend.reject_request_duration 2592000000\n\n##好友请求过期时间，单位是毫秒，默认是7天，0为无限长期限。\nfriend.request_expiration_duration 604800000\n\n##好友请求限制频率，一个用户24小时之内允许请求好友的次数，默认不限频。\nfriend.request_rate_limit 30\n\n##如果搜索电话号码，24小时内搜索错误号码几次就不再允许电话号码搜素。防止有人遍历搜索电话号码\nfriend.search_mobile_empty_rate_limit 5\n\n##如果搜索用户，24小时内搜索次数。防止有人遍历用户名或者用户ID乱加好友。另外可以禁止ID搜索friend.disable_user_id_search\nfriend.search_rate_limit 100\n\n##请求添加机器人为好友时，机器人是否自动接受，默认为true\nfriend.robot_auto_accept true\n\n## 聊天室观众空闲退出时间，单位为毫秒，默认为15分钟，0为永远不退出\nchatroom.participant_idle_time 900000\n\n## 用户向聊天室发送消息，自动加入聊天室\nchatroom.rejoin_when_active true\n\n## 当一个聊天室不存在时，如果有用户加入就自动创建\nchatroom.create_when_not_exist true\n\n## 一个用户同一时刻只能加入一个聊天室。\n## 当一个客户端加入一个聊天室时，如果这个客户端已经加入另外一个聊天室了，会自动退出之前的聊天室。\n## 当一个客户端加入一个聊天室时，如果这个用户的其他端已经加入一个聊天室了，kickoff_other_platform为true时会自动退出之前的聊天室，为false时会返回225的错误码。\n## 当自动退出聊天室时，客户端不会收到任何通知，只是不会再收到消息。\nchatroom.kickoff_other_platform true\n\n## 是否允许群主不受限制地撤回自己发送的消息。false可以${message.recall_time_limit}撤回自己的消息；true可以撤回任意时间自己的消息。默认为true。\ngroup.allow_owner_recall_self_msg true\n\n## 是否允许群管理员不受限制地撤回自己发送的消息。false可以${message.recall_time_limit}撤回自己的消息；true可以撤回任意时间自己的消息。默认为false。\ngroup.allow_manager_recall_self_msg false\n\n## 是否允许客户端发送操作群的自定义群通知消息\ngroup.allow_client_custom_operation_notification true\n\n## 是否允许机器人发送操作群的自定义群通知消息\ngroup.allow_robot_custom_operation_notification true\n\n## 当群成员退出或者被移除时，是否同时给管理员和相关人员发送显式通知消息。\n## 0 不发送，1 退群时发送，2 踢人时发送，3 退群和踢人时都发送。\n## 如果应用需要退群或者踢人不通知普通成员，请设置此参数为3，然后修改客户端踢人或退群消息的flag为not_presist。\ngroup.visible_quit_or_kickoff_notification 0\n\n## 禁止客户端群操作。第1位是禁止创建群组，第2位是禁止销毁群组，3位禁止加入群，4位禁止退出群，5位禁止邀请群成员，6位禁止移出群成员，7位禁止转移群，8位禁止设置群管理员，9位禁止白名单处理，10位禁止群禁言，11位禁止修改群组信息，12位禁止群成员禁言。\n## 如果有客户端有被破解的风险，可以禁止客户端群操作，然后通过Server API操作。Server API不受限制。\n#group.forbidden_client_operation 0xFFF\n\n## 是否禁止陌生人拉人入群，默认为false\ngroup.disable_stranger_invite false\n\n## 创建群组或者加人时。可能会有成员加入失败（黑名单，或者不允许陌生人拉入群）。当出现有成员失败时，如果此开关为关，操作会失败。\n## 如果此开关打开，操作会返回成功，另外在群里发送一条通知消息 XXX 拒绝加入群组。默认为开。\ngroup.add_member_allow_part_success true\n\n## 群组信息是否标记删除\ngroup.enable_mark_deletion true\n\n## 隐藏用户信息属性类型，2是性别，3是电话号码，4是邮箱，5是地址，6是公司信息，7是社交账号，8是Extra信息。当需要隐藏多个时以英文逗号分开;\n## 本配置是为了提高安全性，避免把对应信息同步到客户端，这样就能防止程序被破解从而拿到用户关键信息。仅对客户端有效，server api不受影响。\n## 注意，修改本配置不会对已经同步的信息产生影响。\n#user.hide_properties 3,4\n\n## 销毁用户时，用户信息会被清空，deleted字段设置为1，这个开关控制是否保留用户昵称，默认为true。\nuser.keep_display_name_when_destroy true\n\n## 销毁用户时deleted字段设置为1，这个开关控制是否保留其他信息，默认是false。\nuser.keep_full_info_when_destroy false\n\n## 销毁用户时，如果user.keep_full_info_when_destroy为true，会保留所有信息，这个开关控制是否保留这个用户信息的电话号码，默认为false。\n## 当保留所有信息且保留电话号码时，用户如果再注册会用到原来的UID，能够看到原来用户的消息，需要考虑一下是否让已删除用户再次注册登录看到之前的消息。\nuser.keep_mobile_when_destroy false\n\n## 销毁用户时是否保留归属于这个用户的所有消息记录，默认为false。\nuser.keep_messages_when_destroy false\n\n# 好友/好友请求/用户设置 这三类数据同步的最大条目数。之前是客户第一次登录时，会把所有的对应数据一次下载到客户端，但如果有特别多的信息，会导致无法同步到客户端，\n# 因此需要分段多次同步，此开关定义了每次同步的数据的条数。此需要客户端支持，客户端SDK在2021.5.25日后支持此功能。如果确认所有客户端都在这个日志之后才可以打开此设置。\n#sync.data_part_size 1000\n\n## 是否关闭api/version接口。api/version方法可以用来检查IM服务版本，上线确认无问题后，可以关掉这个接口。\n#http.close_api_version false\n\n#*********************************************************************\n# 限频配置\n#*********************************************************************\n##API接口限频设置，时间是10秒内允许的请求次数。\n##管理api频率限制，默认是10秒10000次。\nhttp.admin.rate_limit 10000\n##机器人api频率限制，默认是10秒1000次，按照机器人ID区分。\nhttp.robot.rate_limit 1000\n##频道api频率限制，默认是10秒1000次，按照频道ID区分。\nhttp.channel.rate_limit 1000\n\n##客户端请求频率限制，默认是5秒100次。通常情况下不要修改这个值。\nclient.request_rate_limit 100\n\n#*********************************************************************\n# Media server configuration\n#*********************************************************************\n##是否使用七牛云存储。1使用七牛；0使用内存文件服务器。默认的七牛账户信息不可用，请在七牛官网申请账户并配置\n##专业版另外支持阿里云存储和野火私有存储，关于野火私有存储请参考：https://github.com/wildfirechat/WF-minio\n##关于对象存储的详细信息请参考：https://docs.wildfirechat.cn/server/oss.html\nmedia.server.use_qiniu 0\n\n# qiniu media server configuration\n## 上传地址，不同的区域，上传地址也不同，请注意现在正确的地址\nqiniu.server_url  http://up.qbox.me\nqiniu.access_key tU3vdBK5BL5j4N7jI5N5uZgq_HQDo170w5C9Amnn\nqiniu.secret_key YfQIJdgp5YGhwEw14vGpaD2HJZsuJldWtqens7i5\n## bucket名字及Domain\nqiniu.bucket_general_name media\nqiniu.bucket_general_domain http://cdn.wildfirechat.cn\nqiniu.bucket_image_name media\nqiniu.bucket_image_domain http://cdn.wildfirechat.cn\nqiniu.bucket_voice_name media\nqiniu.bucket_voice_domain http://cdn.wildfirechat.cn\nqiniu.bucket_video_name media\nqiniu.bucket_video_domain http://cdn.wildfirechat.cn\nqiniu.bucket_file_name media\nqiniu.bucket_file_domain http://cdn.wildfirechat.cn\nqiniu.bucket_sticker_name media\nqiniu.bucket_sticker_domain http://cdn.wildfirechat.cn\nqiniu.bucket_moments_name media\nqiniu.bucket_moments_domain http://cdn.wildfirechat.cn\nqiniu.bucket_portrait_name storage\nqiniu.bucket_portrait_domain http://cdn2.wildfirechat.cn\nqiniu.bucket_favorite_name storage\nqiniu.bucket_favorite_domain http://cdn2.wildfirechat.cn\n## custom的桶是给客户预留的，客户可以上传自己的文件到这3个桶中，野火不会用到这几个桶。如果不需要，可以忽略这几个配置\nqiniu.bucket_custom1_name temp1\nqiniu.bucket_custom1_domain http://temp1.wildfirechat.cn\nqiniu.bucket_custom2_name temp2\nqiniu.bucket_custom2_domain http://temp2.wildfirechat.cn\nqiniu.bucket_custom3_name temp3\nqiniu.bucket_custom3_domain http://temp3.wildfirechat.cn\n## 如果配置网盘服务，需要配置这个\nqiniu.bucket_pan_name pan\nqiniu.bucket_pan_domain http://pan.wildfirechat.cn\n\n##媒体类型分类\n#Media_Type_GENERAL = 0,\n#Media_Type_IMAGE = 1,\n#Media_Type_VOICE = 2,\n#Media_Type_VIDEO = 3,\n#Media_Type_FILE = 4,\n#Media_Type_PORTRAIT = 5,\n#Media_Type_FAVORITE = 6,\n#Media_Type_STICKER = 7,\n#Media_Type_MOMENTS = 8\n\n# local media server configuration\n# 本地媒体服务器配置。\nlocal.media.storage.root media\n# 如果使用内置文件存储，文件上传后地址默认为 http://server.ip:http_port/fs/5/2021/03/27/08/filename。fs目录下按照类型存放文件，媒体类型见上面注释，比如5就是Media_Type_PORTRAIT，是客户端的头像文件。\n# 如果需要使用nginx添加https支持，请打开下面配置，这样客户端得到的文件地址为 https://example.com/media/fs/5/2021/03/27/08/filename。\n# 需要nginx把请求从https://example.com/media/fs 转到 http://server.ip:http_port/fs。注意需要带上所有header。\n# 尽管内置文件存储可以使用，但是我们还是建议使用专业级别的对象存储服务，社区版可以使用七牛，专业版另外支持阿里云和也是私有对象存储。详情请参考 https://docs.wildfirechat.cn/server/oss.html\n# local.media.storage.remote_server_url https://example.com/media\n\n# 是否支持任意多端登陆，为true时支持任意平台任意多个客户端同时登录；为false时每个平台只支持一个端登录，但不同平台可以同时登录。\n# Android/iOS为移动平台，windows/mac/linux为pc平台，web为web平台，小程序为小程序平台。\n# 建议使用false\nserver.multi_endpoint false\n\n## 是否支持PC多端登陆，当server.multi_endpoint为true时，此开关无意义，当为false时，可以单独打开PC端多端登录。\nserver.multi_pc_endpoint false\n\n## 是否支持PAD多端登陆，当server.multi_endpoint为true时，此开关无意义，当为false时，可以单独打开PAD端多端登录。\nserver.multi_pad_endpoint false\n\n## 是否支持可穿戴设备多端登陆，当server.multi_endpoint为true时，此开关无意义，当为false时，可以单独打开可穿戴设备多端登录。\nserver.multi_wearable_endpoint false\n\n## 是否支持TV设备多端登陆，当server.multi_endpoint为true时，此开关无意义，当为false时，可以单独打开TV多端登录。\nserver.multi_tv_endpoint false\n\n# 多平台连接状态通知（仅当multi_endpoint为false时有效），true时移动端可以收到pc或pad或web端登录的通知。\nserver.multi_platform_notification true\n\n# 当pc或者web在线时，手机是否默认静音，默认为true。注意仅影响默认值，用户可以手动切换是否静音。\n# 如果这里改为false，客户端那边需要同步修改pc在线默认通知状态，方法是client的setDefaultSilentWhenPcOnline函数。\nserver.mobile_default_silent_when_pc_online true\n\n## 客户端是否支持kickoff事件。当客户端被其他端登录踢出时，如果此开关为false时，客户端协议栈上报secret_mismatch。如果此开关为ture时，客户端协议栈上报kicked_off。\n## 客户端被踢时上报kicked_off是在2021.9.15之后才加上的。如果客户端协议栈全部为此日期之后的版本才可以打开此开关。\nserver.client_support_kickoff_event true\n\n#*********************************************************************\n# Push server configuration\n#*********************************************************************\n##推送服务项目地址：https://github.com/wildfirechat/push_server。\n##安卓推送服务器地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\npush.android.server.address http://localhost:8085/android/push\n\n##苹果推送服务器地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\npush.ios.server.address http://localhost:8085/ios/push\n\n##鸿蒙推送服务器地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\npush.harmony.server.address http://localhost:8085/harmony/push\n\n#*********************************************************************\n# 监控配置\n#*********************************************************************\n##异常事件产生回调\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#monitor.exception_event_address http://localhost:8888/im_exception_event/\n\n#*********************************************************************\n# 各种事件回调\n#*********************************************************************\n##用户在线状态事件回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#user.online_status_callback http://localhost:8888/im_event/user/online\n\n##用户信息变动事件回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#relation.relation_update_callback http://localhost:8888/im_event/user/relation\n\n##用户信息变动事件回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#user.user_info_update_callback http://localhost:8888/im_event/user/info\n\n##消息转发地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#message.forward.url http://localhost:8888/im_event/message\n##需要转发的消息类型，当有多个时以英文逗号分割，可以用-来指定区间，注意区间不能太大，因为要把区间内的所有数字都放入到Set中。如果转发所有消息，请注释掉配置或者设置为空\n#message.forward.types 1,2,3,5-10\n##需要转发的消息类型，当有多个时以英文逗号分割，可以用-来指定区间，注意区间不能太大，因为要把区间内的所有数字都放入到Set中。\n#message.forward.exclude_types 1,2,3,5-10\n\n##敏感消息转发地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#message.sensitive.forward.url http://localhost:8888/im_event/message\n\n##提醒消息转发地址，@全体用户和@某个用户消息会回调此地址。\n##此转发不受${message.forward.types}和${message.forward.exclude_types}限制。\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#message.mentionmsg.forward.url http://localhost:8888/im_event/message\n\n##撤回消息转发地址，当用户撤回消息会回调此地址。\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#message.recallmsg.forward.url http://localhost:8888/im_event/recall_message\n\n##设备信息转发地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#things_message.forward.url http://localhost:8087/im_event/things/message\n\n##群组信息变动事件回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#group.group_info_update_callback http://localhost:8888/im_event/group/info\n\n##群组信息变动事件回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#group.group_member_update_callback http://localhost:8888/im_event/group/member\n\n##频道信息变动回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#channel.channel_info_update_callback http://localhost:8888/im_event/channel/info\n\n##聊天室信息变动回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#chatroom.chatroom_info_update_callback http://localhost:8888/im_event/chatroom/info\n\n##聊天室成员变动回调地址\n##注意回调是单线程回调，接收服务必须在同一内网，且异步处理快速返回，否则会有延迟问题！！\n#chatroom.chatroom_member_update_callback http://localhost:8888/im_event/chatroom/member\n\n#*********************************************************************\n# Netty Configuration\n#\n# Linux systems can use epoll instead of nio. To get a performance\n# gain and reduced GC.\n# http://netty.io/wiki/native-transports.html for more information\n#*********************************************************************\n# 如果是linux系统，一定要打开下面这个参数，能大幅度提高性能。默认只支持x86_64架构。如果是arm64架构，可以按照项目说明来更新epoll SDK。其他架构不支持epoll。\n#netty.epoll true\n\n#*********************************************************************\n# Sensitive configuration\n#*********************************************************************\n## 内置文本敏感词过滤处理方法，当命中敏感词后，消息会被记录到t_sensitive_messages表中，然后根据type类型做不同的处理，处理方式如下：\n## 0 发送失败；1 发送成功但消息被服务器直接丢弃；2 命中的敏感词被替换成***然后正常发送；3 正常发送。\n## 如果开启 message.sensitive.forward.url 配置，命中敏感词的消息还会被回调到这个地址\nsensitive.filter.type 2\n\n## 敏感词是否只处理消息。如果为true，只过滤消息；如果为false，会同时过滤用户昵称、群组名和群昵称。\n## 除了消息之外的信息只支持内部敏感词处理，不支持外置审核。\nsensitive.only_message false\n\n## 敏感词添加或者删除有2种方式，一种是通过Server API进行，这种方式会立即生效。另外一种方法是修改数据库，直接中数据库的t_sensitive_word表中处理\n## 修改数据库的方法不会立即生效，IM服务会2个小时重新加载一次敏感词。所以如果直接修改敏感词表，需要等2个小时，或者重启才能生效。\n\n## 如果内置敏感词库无法满足您的需求，可以开发部署独立敏感词审核服务。配置如下地址和消息类型，IM服务会把指定消息类型的消息回调到指定地址，内置的敏感词审核和敏感词转发功能就不再起作用了。\n## 审核服务返回状态码200表示继续发送，如果需要替换内容，返回状态码200并且内容为替换后的内容。返回403表示不允许发送。其它错误继续发送。\n## 独立审核服务地址，IM服务会post SendMessageData。如果需要修改消息内容，返回 MessagePayload。请参考应用服务中 \"/message/censor\" Mapping.\n#sensitive.remote_server_url http://192.168.3.202:8888/message/censor\n## 需要进行敏感词审核的消息类型，当有多个时以英文逗号分割\n#sensitive.remote_sensitive_message_type 1,2,3\n## 如果远程审核服务返回403，返回给发送端发送失败还是成功？实际上这个值影响发送响应是否等待审核结果，当为false时，消息发送给审核服务就立即返回成功给客户端。\n## 当为true时，消息发送给审核服务，等待审核结果，如果结果为继续发送就返回给客户端为成功，结果为禁止发送就返回失败给客户端。\n## 客户端操作的超时一般为10s左右，且考虑到复杂的网络情况，建议处理时间不要超过3s。建议这个值为false。\n#sensitive.remote_fail_when_matched false\n"
  },
  {
    "path": "distribution/src/main/rpm/install.sh",
    "content": "set -e\n\ncd /opt/im-server\ntar -xzvf distribution*.tar.gz\n\nsed -i 's/h2db.path .\\/h2db\\/wfchat/h2db.path \\/var\\/lib\\/im-server\\/h2db\\/imdb/' /opt/im-server/config/wildfirechat.conf\nsed -i 's/local.media.storage.root .\\/media/local.media.storage.root \\/var\\/lib\\/im-server\\/media/' /opt/im-server/config/wildfirechat.conf\nsed -i 's/<Property name=\"MSG_LOG_HOME\">.\\/logs<\\/Property>/<Property name=\"MSG_LOG_HOME\">\\/var\\/log\\/im-server<\\/Property>/' /opt/im-server/config/log4j2.xml\nsed -i 's/WILDFIRECHAT_CONFIG_PATH=$WILDFIRECHAT_HOME/WILDFIRECHAT_CONFIG_PATH=\\/etc\\/im-server/' /opt/im-server/bin/wildfirechat.sh\n\nif [ ! -d /etc/im-server ]; then\nmkdir /etc/im-server\nfi\n\nif [ ! -d /var/log/im-server ]; then\nmkdir /var/log/im-server\nfi\n\nmv -f  /opt/im-server/config /etc/im-server\nsystemctl daemon-reload\n\necho \"IM server folders:\"\necho \"/etc/im-server/config     config\"\necho \"/opt/im-server            binary files\"\necho \"/var/log/im-server        logs\"\necho \"/var/lib/im-server/h2db   embed db\"\necho \"/var/lib/im-server/media  embed media files\"\n"
  },
  {
    "path": "distribution/src/main/rpm/uninstall.sh",
    "content": "set -e\nrm -rf /opt/im-server\nrm -rf /etc/im-server\nrm -rf /var/log/im-server\nrm -rf /usr/lib/systemd/system/im-server.service\n\nif [ -d /var/lib/im-server/h2db ]; then\necho \"IM embed db file not deleted in path /var/lib/im-server/h2db, if you don't need it anymore, please remove it manually\"\nfi\n\nif [ -d /var/lib/im-server/media ]; then\necho \"IM embed media files not deleted in path /var/lib/im-server/media, if you don't need it anymore, please remove it manually\"\nfi\n\nsystemctl daemon-reload\n\n"
  },
  {
    "path": "distribution/src/main/scripts/stop.sh",
    "content": "#!/bin/sh\n\npid=`ps -ef | grep wildfirechat.server.Server | grep -v grep | awk '{print $2}'`\n\nif [ -z $pid ]; then\n    echo \"野火IM服务不存在\"\n    exit 0\nfi\n\nkill -15 $pid\n\nfor i in {1..30}\ndo\n  pid=`ps -ef | grep wildfirechat.server.Server | grep -v grep | awk '{print $2}'`\n  if [ -z $pid ]; then\n    echo \"野火IM服务已结束\"\n    exit 0\n  else\n    echo \"正在结束中，请等待...\"\n    sleep 1\n  fi\ndone\n\necho \"正常结束失败，强制结束！\"\nkill -9 $pid\n"
  },
  {
    "path": "distribution/src/main/scripts/wildfirechat.bat",
    "content": "@ECHO OFF\n\nset \"CURRENT_DIR=%cd%\"\nset \"WILDFIRECHAT_HOME=%CURRENT_DIR%\"\nif exist \"%WILDFIRECHAT_HOME%\\bin\\wildfirechat.bat\" goto okHome\ncd ..\nset \"WILDFIRECHAT_HOME=%cd%\"\nset \"CURRENT_DIR=%cd%\"\n:gotHome\nif exist \"%WILDFIRECHAT_HOME%\\bin\\wildfirechat.bat\" goto okHome\n    echo The WILDFIRECHAT_HOME environment variable is not defined correctly\n    echo This environment variable is needed to run this program\ngoto end\n:okHome\n\nrem Set JavaHome if it exists\nif exist [ \"%JAVA_HOME%\\bin\\java\" ]  (\n    set \"JAVA=\"%JAVA_HOME%\\bin\\java\"\"\n) else (\n    set \"JAVA=\"java\"\"\n)\n\necho Using JAVA_HOME:       \"%JAVA_HOME%\"\necho Using WILDFIRECHAT_HOME:   \"%WILDFIRECHAT_HOME%\"\n\nrem  set LOG_CONSOLE_LEVEL=info\nrem  set LOG_FILE_LEVEL=fine\nset JAVA_OPTS=\nset JAVA_OPTS_SCRIPT=-XX:+HeapDumpOnOutOfMemoryError -Djava.awt.headless=true\nset WILDFIRECHAT_PATH=%WILDFIRECHAT_HOME%\nset LOG_FILE=%WILDFIRECHAT_HOME%\\config\\log4j2.xml\nset HZ_CONF_FILE=%WILDFIRECHAT_HOME%\\config\\hazelcast.xml\nset C3P0_CONF_FILE=%WILDFIRECHAT_HOME%\\config\\c3p0-config.xml\n\nrem Use the Hotspot garbage-first collector.\nset JAVA_OPTS=%JAVA_OPTS%  -XX:+UseG1GC\n\nrem Have the JVM do less remembered set work during STW, instead\nrem preferring concurrent GC. Reduces p99.9 latency.\nset JAVA_OPTS=%JAVA_OPTS%  -XX:G1RSetUpdatingPauseTimePercent=5\n\nrem Main G1GC tunable: lowering the pause target will lower throughput and vise versa.\nrem 200ms is the JVM default and lowest viable setting\nrem 1000ms increases throughput. Keep it smaller than the timeouts.\nset JAVA_OPTS=%JAVA_OPTS%  -XX:MaxGCPauseMillis=500\n\nrem Optional G1 Settings\n\nrem  Save CPU time on large (>= 16GB) heaps by delaying region scanning\nrem  until the heap is 70% full. The default in Hotspot 8u40 is 40%.\nrem set JAVA_OPTS=%JAVA_OPTS%  -XX:InitiatingHeapOccupancyPercent=70\n\nrem  For systems with > 8 cores, the default ParallelGCThreads is 5/8 the number of logical cores.\nrem  Otherwise equal to the number of cores when 8 or less.\nrem  Machines with > 10 cores should try setting these to <= full cores.\nrem set JAVA_OPTS=%JAVA_OPTS%  -XX:ParallelGCThreads=16\n\nrem  By default, ConcGCThreads is 1/4 of ParallelGCThreads.\nrem  Setting both to the same value can reduce STW durations.\nrem set JAVA_OPTS=%JAVA_OPTS%  -XX:ConcGCThreads=16\n\nrem rem GC logging options -- uncomment to enable\n\nrem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintGCDetails\nrem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintGCDateStamps\nrem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintHeapAtGC\nrem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintTenuringDistribution\nrem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintGCApplicationStoppedTime\nrem set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintPromotionFailure\nrem set JAVA_OPTS=%JAVA_OPTS% -XX:PrintFLSStatistics=1\nrem set JAVA_OPTS=%JAVA_OPTS% -XX:+UseGCLogFileRotation\nrem set JAVA_OPTS=%JAVA_OPTS% -XX:NumberOfGCLogFiles=10\nrem set JAVA_OPTS=%JAVA_OPTS% -XX:GCLogFileSize=10M\"\n\nrem If the JDK version is 9 or above, please open this configuration.\nrem set JAVA_OPTS=%JAVA_OPTS% --add-modules java.se --add-exports java.base/jdk.internal.ref=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.management/sun.management=ALL-UNNAMED --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED\n\necho \"Please set Xmx and Xms parameters!\"\necho \"Please set Xmx and Xms parameters!\"\necho \"Please set Xmx and Xms parameters!\"\n\nrem set JAVA_OPTS=%JAVA_OPTS% -Xmx2G\nrem set JAVA_OPTS=%JAVA_OPTS% -Xms2G\n\n%JAVA% -server %JAVA_OPTS% %JAVA_OPTS_SCRIPT% -Dlog4j.configurationFile=%LOG_FILE% -Dcom.mchange.v2.c3p0.cfg.xml=%C3P0_CONF_FILE% -Dhazelcast.configuration=%HZ_CONF_FILE% -Dwildfirechat.path=%WILDFIRECHAT_PATH% -cp %WILDFIRECHAT_HOME%\\lib\\* cn.wildfirechat.server.Server\n"
  },
  {
    "path": "distribution/src/main/scripts/wildfirechat.sh",
    "content": "#!/bin/sh\n\ncd \"$(dirname \"$0\")\"\n\n# resolve links - $0 may be a softlink\nPRG=\"$0\"\n\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    PRGDIR=`dirname \"$PRG\"`\n    cd $PRGDIR\n    PRG=\"`pwd`\"/\"$link\"\n  fi\ndone\n\nPRGDIR=`dirname \"$PRG\"`\ncd ..\nWILDFIRECHAT_HOME=`pwd`\n\n\nexport WILDFIRECHAT_HOME\n\necho $WILDFIRECHAT_HOME\n\nif [ -f \"${JAVA_HOME}/bin/java\" ]; then\n   JAVA=${JAVA_HOME}/bin/java\nelse\n   JAVA=java\nfi\nexport JAVA\n\n$JAVA -version\n\nWILDFIRECHAT_CONFIG_PATH=$WILDFIRECHAT_HOME\n\nLOG_FILE=$WILDFIRECHAT_CONFIG_PATH/config/log4j2.xml\nHZ_CONF_FILE=$WILDFIRECHAT_CONFIG_PATH/config/hazelcast.xml\nC3P0_CONF_FILE=$WILDFIRECHAT_CONFIG_PATH/config/c3p0-config.xml\n\n\n#LOG_CONSOLE_LEVEL=info\n#LOG_FILE_LEVEL=fine\nJAVA_OPTS_SCRIPT=\"-XX:+HeapDumpOnOutOfMemoryError -Djava.awt.headless=true\"\n\n## Use the Hotspot garbage-first collector.\nJAVA_OPTS=\"$JAVA_OPTS -XX:+UseG1GC\"\n\n## Have the JVM do less remembered set work during STW, instead\n## preferring concurrent GC. Reduces p99.9 latency.\nJAVA_OPTS=\"$JAVA_OPTS -XX:G1RSetUpdatingPauseTimePercent=5\"\n\n## Main G1GC tunable: lowering the pause target will lower throughput and vise versa.\n## 200ms is the JVM default and lowest viable setting\n## 1000ms increases throughput. Keep it smaller than the timeouts.\nJAVA_OPTS=\"$JAVA_OPTS -XX:MaxGCPauseMillis=500\"\n\n## Optional G1 Settings\n\n# Save CPU time on large (>= 16GB) heaps by delaying region scanning\n# until the heap is 70% full. The default in Hotspot 8u40 is 40%.\n#JAVA_OPTS=\"$JAVA_OPTS -XX:InitiatingHeapOccupancyPercent=70\"\n\n# For systems with > 8 cores, the default ParallelGCThreads is 5/8 the number of logical cores.\n# Otherwise equal to the number of cores when 8 or less.\n# Machines with > 10 cores should try setting these to <= full cores.\n#JAVA_OPTS=\"$JAVA_OPTS -XX:ParallelGCThreads=16\"\n\n# By default, ConcGCThreads is 1/4 of ParallelGCThreads.\n# Setting both to the same value can reduce STW durations.\n#JAVA_OPTS=\"$JAVA_OPTS -XX:ConcGCThreads=16\"\n\n### GC logging options -- uncomment to enable\n\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintGCDetails\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintGCDateStamps\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintHeapAtGC\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintTenuringDistribution\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintGCApplicationStoppedTime\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintPromotionFailure\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:PrintFLSStatistics=1\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+UseGCLogFileRotation\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:NumberOfGCLogFiles=10\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:GCLogFileSize=10M\"\n\n#如果JDK版本是9及以上，请打开这个配置\n#JAVA_OPTS=\"$JAVA_OPTS --add-modules java.se --add-exports java.base/jdk.internal.ref=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.management/sun.management=ALL-UNNAMED --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED\"\n\necho \"警告：没有设置JVM内存参数！\"\necho \"请设置JVM参数Xmx和Xms，设置为您为IM服务预留的内存大小，注意需要刨除操作系统占用，如果有其它系统也需要相应去除占用，还需要减去堆外内存占用。\"\necho \"建议设置为总内存的60%以下，比如16G总内存，Xmx可以设置为9G\"\necho \"\"\n#JAVA_OPTS=\"$JAVA_OPTS -Xmx2G\"\n#JAVA_OPTS=\"$JAVA_OPTS -Xms2G\"\n\n\n$JAVA -server $JAVA_OPTS $JAVA_OPTS_SCRIPT -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -Dlog4j.configurationFile=\"file:$LOG_FILE\" -Dlog4j2.formatMsgNoLookups=true -Dcom.mchange.v2.c3p0.cfg.xml=\"$C3P0_CONF_FILE\" -Dhazelcast.configuration=$HZ_CONF_FILE -Dwildfirechat.path=\"$WILDFIRECHAT_CONFIG_PATH\" -cp \"$WILDFIRECHAT_HOME/lib/*\" cn.wildfirechat.server.Server\n"
  },
  {
    "path": "docker/Dockerfile",
    "content": "FROM openjdk:8-jre-alpine\n\nADD distribution-*-bundle-tar.tar.gz /opt/im-server/\n\nRUN sed -i 's/#JAVA_OPTS=\"$JAVA_OPTS -Xmx128M\"/JAVA_OPTS=\"$JAVA_OPTS -Xmx$JVM_XMX\"/g' /opt/im-server/bin/wildfirechat.sh\nRUN sed -i 's/#JAVA_OPTS=\"$JAVA_OPTS -Xms128M\"/JAVA_OPTS=\"$JAVA_OPTS -Xms$JVM_XMS\"/g' /opt/im-server/bin/wildfirechat.sh\n\nRUN chmod a+x /opt/im-server/bin/wildfirechat.sh\n\nWORKDIR /opt/im-server\n\nVOLUME /opt/im-server/config\nVOLUME /opt/im-server/logs\nVOLUME /opt/im-server/h2db\nVOLUME /opt/im-server/media\n\nEXPOSE 80/tcp 1883/tcp 8083/tcp 8084/tcp 18080/tcp\n\nENV JVM_XMX 256M\nENV JVM_XMS 256M\n\n\nCMD ./bin/wildfirechat.sh\n"
  },
  {
    "path": "docker/README.md",
    "content": "# 野火IM服务docker使用说明\n\n## 编译镜像\n首先需要先编译IM服务，在项目根目录下使用下面命令编译\n```\nmvn clean package\n```\n生成的软件包在```distribution/target/distribution-XX-bundle-tar.tar.gz```，把此软件包拷贝到docker目录下。\n\n然后进入到docker目录下，编译镜像\n```\nsudo docker build -t im-server .\n```\n\n## 运行\n配置：\n运行需要手动指定配置目录，手动指定配置目录的方法如下，其中$PATH_TO_CONFIG为im配置目录，需要为绝对路径，模版为```distribution/src/main/resources```目录。另外需要创建h2数据库目录（如果用mysql就不需要了）、日志目录、内置存储服务目录（如果使用其它对象存储服务就不需要了）。h2数据库目录/日志目录/内置存储服务目录需要有写权限，因为IM服务会写入文件。\n```\nsudo docker run -it --name im-server -v $PATH_TO_CONFIG:/opt/im-server/config -v $PATH_TO_LOGS:/opt/im-server/logs -v $PATH_TO_H2DB:/opt/im-server/h2db -v $PATH_TO_MEDIA:/opt/im-server/media -e JVM_XMX=256M -e JVM_XMS=256M -p 80:80 -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 18080:18080 im-server\n```\n\n## 导出镜像\n```\nsudo docker save -o im-server.tar im-server\n```\n\n## 导入镜像\n```\nsudo docker load -i im-server.tar\n```\n"
  },
  {
    "path": "flyway_repaire_migrate_38.sql",
    "content": "--  IM服务在2020.10.6-2020-11.2号之间的版本升级到最新版本时，可能会提示出现如下的错误：\n--  Exception in thread \"main\" org.flywaydb.core.api.FlywayException: Validate failed: Detected resolved migration not applied to database: 38\n--      at org.flywaydb.core.Flyway.doValidate(Flyway.java:1482)\n--      at org.flywaydb.core.Flyway.access$100(Flyway.java:85)\n--      at org.flywaydb.core.Flyway$1.execute(Flyway.java:1364)\n--      at org.flywaydb.core.Flyway$1.execute(Flyway.java:1356)\n--      ...\n--\n--  当出现这个问题后，执行这个sql就可以修复了。\n--\n--\nDROP TABLE IF EXISTS `t_file`;\nCREATE TABLE `t_file` (\n  `_mid` bigint(20) NOT NULL PRIMARY KEY,\n  `_from` varchar(64) NOT NULL,\n  `_type` tinyint NOT NULL DEFAULT 0,\n  `_target` varchar(64) NOT NULL,\n  `_line` int(11) NOT NULL DEFAULT 0,\n  `_name` varchar(128) DEFAULT '',\n  `_url` varchar(1024) NOT NULL DEFAULT '',\n  `_size` int(11) NOT NULL DEFAULT 0,\n  `_download_count` int(11) DEFAULT 0,\n  `_dt` bigint(20) NOT NULL,\n  INDEX `file_conv_index` (`_type`, `_line`, `_target`, `_mid`),\n  INDEX `file_user_index` (`_from`, `_mid`)\n)\nENGINE = InnoDB\nDEFAULT CHARACTER SET = utf8mb4\nCOLLATE = utf8mb4_unicode_ci;\n\n\nalter table `t_group` modify column `_searchable` int(11) NOT NULL DEFAULT 0;\n\nupdate flyway_schema_history set installed_rank = 40 where version = 40;\n\ninsert into flyway_schema_history values (38,'38','alter group searchable column','SQL','V38__alter_group_searchable_column.sql',-524664704,'root','2020-07-21 14:43:50',1126,1),(39,'39','create files table','SQL','V39__create_files_table.sql',1144437159,'root','2020-08-03 03:15:04',503,1);\n"
  },
  {
    "path": "license-eplv10-aslv20.html",
    "content": "<html xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:w=\"urn:schemas-microsoft-com:office:word\" xmlns=\"http://www.w3.org/TR/REC-html40\"><head>\n\n\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=windows-1252\">\n<meta name=\"ProgId\" content=\"Word.Document\">\n<meta name=\"Generator\" content=\"Microsoft Word 9\">\n<meta name=\"Originator\" content=\"Microsoft Word 9\">\n<link rel=\"File-List\" href=\"http://www.eclipse.org/legal/Eclipse%20EPL%202003_11_10%20Final_files/filelist.xml\">\n<title>Eclipse Public License - Version 1.0 / Apache License - Version 2.0</title>\n<!--[if gte mso 9]><xml>\n <o:DocumentProperties>\n  <o:Revision>2</o:Revision>\n  <o:TotalTime>3</o:TotalTime>\n  <o:Created>2004-03-05T23:03:00Z</o:Created>\n  <o:LastSaved>2004-03-05T23:03:00Z</o:LastSaved>\n  <o:Pages>4</o:Pages>\n  <o:Words>1626</o:Words>\n  <o:Characters>9270</o:Characters>\n   <o:Lines>77</o:Lines>\n  <o:Paragraphs>18</o:Paragraphs>\n  <o:CharactersWithSpaces>11384</o:CharactersWithSpaces>\n  <o:Version>9.4402</o:Version>\n </o:DocumentProperties>\n</xml><![endif]--><!--[if gte mso 9]><xml>\n <w:WordDocument>\n  <w:TrackRevisions/>\n </w:WordDocument>\n</xml><![endif]-->\n<style>\n<!--\n /* Font Definitions */\n@font-face\n\t{font-family:Tahoma;\n\tpanose-1:2 11 6 4 3 5 4 4 2 4;\n\tmso-font-charset:0;\n\tmso-generic-font-family:swiss;\n\tmso-font-pitch:variable;\n\tmso-font-signature:553679495 -2147483648 8 0 66047 0;}\n /* Style Definitions */\np.MsoNormal, li.MsoNormal, div.MsoNormal\n\t{mso-style-parent:\"\";\n\tmargin:0in;\n\tmargin-bottom:.0001pt;\n\tmso-pagination:widow-orphan;\n\tfont-size:12.0pt;\n\tfont-family:\"Times New Roman\";\n\tmso-fareast-font-family:\"Times New Roman\";}\np\n\t{margin-right:0in;\n\tmso-margin-top-alt:auto;\n\tmso-margin-bottom-alt:auto;\n\tmargin-left:0in;\n\tmso-pagination:widow-orphan;\n\tfont-size:12.0pt;\n\tfont-family:\"Times New Roman\";\n\tmso-fareast-font-family:\"Times New Roman\";}\np.BalloonText, li.BalloonText, div.BalloonText\n\t{mso-style-name:\"Balloon Text\";\n\tmargin:0in;\n\tmargin-bottom:.0001pt;\n\tmso-pagination:widow-orphan;\n\tfont-size:8.0pt;\n\tfont-family:Tahoma;\n\tmso-fareast-font-family:\"Times New Roman\";}\n@page Section1\n\t{size:8.5in 11.0in;\n\tmargin:1.0in 1.25in 1.0in 1.25in;\n\tmso-header-margin:.5in;\n\tmso-footer-margin:.5in;\n\tmso-paper-source:0;}\ndiv.Section1\n\t{page:Section1;}\n-->\n</style>\n</head><body style=\"\" lang=\"EN-US\">\n\n<div class=\"Section1\">\n\n<p style=\"text-align: center;\" align=\"center\"><b>Eclipse Public License - v 1.0</b>\n</p>\n\n<p><span style=\"font-size: 10pt;\">THE ACCOMPANYING PROGRAM IS PROVIDED UNDER\nTHE TERMS OF THIS ECLIPSE PUBLIC LICENSE (\"AGREEMENT\"). ANY USE,\nREPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE\nOF THIS AGREEMENT.</span> </p>\n\n<p><b><span style=\"font-size: 10pt;\">1. DEFINITIONS</span></b> </p>\n\n<p><span style=\"font-size: 10pt;\">\"Contribution\" means:</span> </p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">a)\nin the case of the initial Contributor, the initial code and documentation\ndistributed under this Agreement, and<br clear=\"left\">\nb) in the case of each subsequent Contributor:</span></p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">i)\nchanges to the Program, and</span></p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">ii)\nadditions to the Program;</span></p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">where\nsuch changes and/or additions to the Program originate from and are distributed\nby that particular Contributor. A Contribution 'originates' from a Contributor\nif it was added to the Program by such Contributor itself or anyone acting on\nsuch Contributor's behalf. Contributions do not include additions to the\nProgram which: (i) are separate modules of software distributed in conjunction\nwith the Program under their own license agreement, and (ii) are not derivative\nworks of the Program. </span></p>\n\n<p><span style=\"font-size: 10pt;\">\"Contributor\" means any person or\nentity that distributes the Program.</span> </p>\n\n<p><span style=\"font-size: 10pt;\">\"Licensed Patents \" mean patent\nclaims licensable by a Contributor which are necessarily infringed by the use\nor sale of its Contribution alone or when combined with the Program. </span></p>\n\n<p><span style=\"font-size: 10pt;\">\"Program\" means the Contributions\ndistributed in accordance with this Agreement.</span> </p>\n\n<p><span style=\"font-size: 10pt;\">\"Recipient\" means anyone who\nreceives the Program under this Agreement, including all Contributors.</span> </p>\n\n<p><b><span style=\"font-size: 10pt;\">2. GRANT OF RIGHTS</span></b> </p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">a)\nSubject to the terms of this Agreement, each Contributor hereby grants Recipient\na non-exclusive, worldwide, royalty-free copyright license to<span style=\"color: red;\"> </span>reproduce, prepare derivative works of, publicly\ndisplay, publicly perform, distribute and sublicense the Contribution of such\nContributor, if any, and such derivative works, in source code and object code\nform.</span></p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">b)\nSubject to the terms of this Agreement, each Contributor hereby grants\nRecipient a non-exclusive, worldwide,<span style=\"color: green;\"> </span>royalty-free\npatent license under Licensed Patents to make, use, sell, offer to sell, import\nand otherwise transfer the Contribution of such Contributor, if any, in source\ncode and object code form. This patent license shall apply to the combination\nof the Contribution and the Program if, at the time the Contribution is added\nby the Contributor, such addition of the Contribution causes such combination\nto be covered by the Licensed Patents. The patent license shall not apply to\nany other combinations which include the Contribution. No hardware per se is\nlicensed hereunder. </span></p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">c)\nRecipient understands that although each Contributor grants the licenses to its\nContributions set forth herein, no assurances are provided by any Contributor\nthat the Program does not infringe the patent or other intellectual property\nrights of any other entity. Each Contributor disclaims any liability to Recipient\nfor claims brought by any other entity based on infringement of intellectual\nproperty rights or otherwise. As a condition to exercising the rights and\nlicenses granted hereunder, each Recipient hereby assumes sole responsibility\nto secure any other intellectual property rights needed, if any. For example,\nif a third party patent license is required to allow Recipient to distribute\nthe Program, it is Recipient's responsibility to acquire that license before\ndistributing the Program.</span></p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">d)\nEach Contributor represents that to its knowledge it has sufficient copyright\nrights in its Contribution, if any, to grant the copyright license set forth in\nthis Agreement. </span></p>\n\n<p><b><span style=\"font-size: 10pt;\">3. REQUIREMENTS</span></b> </p>\n\n<p><span style=\"font-size: 10pt;\">A Contributor may choose to distribute the\nProgram in object code form under its own license agreement, provided that:</span>\n</p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">a)\nit complies with the terms and conditions of this Agreement; and</span></p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">b)\nits license agreement:</span></p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">i)\neffectively disclaims on behalf of all Contributors all warranties and\nconditions, express and implied, including warranties or conditions of title\nand non-infringement, and implied warranties or conditions of merchantability\nand fitness for a particular purpose; </span></p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">ii)\neffectively excludes on behalf of all Contributors all liability for damages,\nincluding direct, indirect, special, incidental and consequential damages, such\nas lost profits; </span></p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">iii)\nstates that any provisions which differ from this Agreement are offered by that\nContributor alone and not by any other party; and</span></p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">iv)\nstates that source code for the Program is available from such Contributor, and\ninforms licensees how to obtain it in a reasonable manner on or through a\nmedium customarily used for software exchange.<span style=\"color: blue;\"> </span></span></p>\n\n<p><span style=\"font-size: 10pt;\">When the Program is made available in source\ncode form:</span> </p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">a)\nit must be made available under this Agreement; and </span></p>\n\n<p class=\"MsoNormal\" style=\"margin-left: 0.5in;\"><span style=\"font-size: 10pt;\">b) a\ncopy of this Agreement must be included with each copy of the Program. </span></p>\n\n<p><span style=\"font-size: 10pt;\">Contributors may not remove or alter any\ncopyright notices contained within the Program. </span></p>\n\n<p><span style=\"font-size: 10pt;\">Each Contributor must identify itself as the\noriginator of its Contribution, if any, in a manner that reasonably allows\nsubsequent Recipients to identify the originator of the Contribution. </span></p>\n\n<p><b><span style=\"font-size: 10pt;\">4. COMMERCIAL DISTRIBUTION</span></b> </p>\n\n<p><span style=\"font-size: 10pt;\">Commercial distributors of software may\naccept certain responsibilities with respect to end users, business partners\nand the like. While this license is intended to facilitate the commercial use\nof the Program, the Contributor who includes the Program in a commercial\nproduct offering should do so in a manner which does not create potential\nliability for other Contributors. Therefore, if a Contributor includes the\nProgram in a commercial product offering, such Contributor (\"Commercial\nContributor\") hereby agrees to defend and indemnify every other\nContributor (\"Indemnified Contributor\") against any losses, damages and\ncosts (collectively \"Losses\") arising from claims, lawsuits and other\nlegal actions brought by a third party against the Indemnified Contributor to\nthe extent caused by the acts or omissions of such Commercial Contributor in\nconnection with its distribution of the Program in a commercial product\noffering. The obligations in this section do not apply to any claims or Losses\nrelating to any actual or alleged intellectual property infringement. In order\nto qualify, an Indemnified Contributor must: a) promptly notify the Commercial\nContributor in writing of such claim, and b) allow the Commercial Contributor\nto control, and cooperate with the Commercial Contributor in, the defense and\nany related settlement negotiations. The Indemnified Contributor may participate\nin any such claim at its own expense.</span> </p>\n\n<p><span style=\"font-size: 10pt;\">For example, a Contributor might include the\nProgram in a commercial product offering, Product X. That Contributor is then a\nCommercial Contributor. If that Commercial Contributor then makes performance\nclaims, or offers warranties related to Product X, those performance claims and\nwarranties are such Commercial Contributor's responsibility alone. Under this\nsection, the Commercial Contributor would have to defend claims against the\nother Contributors related to those performance claims and warranties, and if a\ncourt requires any other Contributor to pay any damages as a result, the\nCommercial Contributor must pay those damages.</span> </p>\n\n<p><b><span style=\"font-size: 10pt;\">5. NO WARRANTY</span></b> </p>\n\n<p><span style=\"font-size: 10pt;\">EXCEPT AS EXPRESSLY SET FORTH IN THIS\nAGREEMENT, THE PROGRAM IS PROVIDED ON AN \"AS IS\" BASIS, WITHOUT\nWARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,\nWITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,\nMERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely\nresponsible for determining the appropriateness of using and distributing the\nProgram and assumes all risks associated with its exercise of rights under this\nAgreement , including but not limited to the risks and costs of program errors,\ncompliance with applicable laws, damage to or loss of data, programs or\nequipment, and unavailability or interruption of operations. </span></p>\n\n<p><b><span style=\"font-size: 10pt;\">6. DISCLAIMER OF LIABILITY</span></b> </p>\n\n<p><span style=\"font-size: 10pt;\">EXCEPT AS EXPRESSLY SET FORTH IN THIS\nAGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY\nOF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\nNEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF\nTHE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF\nTHE POSSIBILITY OF SUCH DAMAGES.</span> </p>\n\n<p><b><span style=\"font-size: 10pt;\">7. GENERAL</span></b> </p>\n\n<p><span style=\"font-size: 10pt;\">If any provision of this Agreement is invalid\nor unenforceable under applicable law, it shall not affect the validity or\nenforceability of the remainder of the terms of this Agreement, and without\nfurther action by the parties hereto, such provision shall be reformed to the\nminimum extent necessary to make such provision valid and enforceable.</span> </p>\n\n<p><span style=\"font-size: 10pt;\">If Recipient institutes patent litigation\nagainst any entity (including a cross-claim or counterclaim in a lawsuit)\nalleging that the Program itself (excluding combinations of the Program with\nother software or hardware) infringes such Recipient's patent(s), then such\nRecipient's rights granted under Section 2(b) shall terminate as of the date\nsuch litigation is filed. </span></p>\n\n<p><span style=\"font-size: 10pt;\">All Recipient's rights under this Agreement\nshall terminate if it fails to comply with any of the material terms or\nconditions of this Agreement and does not cure such failure in a reasonable\nperiod of time after becoming aware of such noncompliance. If all Recipient's\nrights under this Agreement terminate, Recipient agrees to cease use and\ndistribution of the Program as soon as reasonably practicable. However,\nRecipient's obligations under this Agreement and any licenses granted by\nRecipient relating to the Program shall continue and survive. </span></p>\n\n<p><span style=\"font-size: 10pt;\">Everyone is permitted to copy and distribute\ncopies of this Agreement, but in order to avoid inconsistency the Agreement is\ncopyrighted and may only be modified in the following manner. The Agreement\nSteward reserves the right to publish new versions (including revisions) of\nthis Agreement from time to time. No one other than the Agreement Steward has\nthe right to modify this Agreement. The Eclipse Foundation is the initial\nAgreement Steward. The Eclipse Foundation may assign the responsibility to\nserve as the Agreement Steward to a suitable separate entity. Each new version\nof the Agreement will be given a distinguishing version number. The Program\n(including Contributions) may always be distributed subject to the version of\nthe Agreement under which it was received. In addition, after a new version of\nthe Agreement is published, Contributor may elect to distribute the Program\n(including its Contributions) under the new version. Except as expressly stated\nin Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to\nthe intellectual property of any Contributor under this Agreement, whether\nexpressly, by implication, estoppel or otherwise. All rights in the Program not\nexpressly granted under this Agreement are reserved.</span> </p>\n\n<p><span style=\"font-size: 10pt;\">This Agreement is governed by the laws of the\nState of New York and the intellectual property laws of the United States of\nAmerica. No party to this Agreement will bring a legal action under this\nAgreement more than one year after the cause of action arose. Each party waives\nits rights to a jury trial in any resulting litigation.</span> </p>\n\n<p class=\"MsoNormal\"><!--[if !supportEmptyParas]-->&nbsp;<!--[endif]--><o:p></o:p></p>\n\n</div>\n\n<div class=\"Section2\">\n\n<p style=\"text-align: center;\" align=\"center\"><b>Apache License</b></br>\nVersion 2.0, January 2004<br/>\nhttp://www.apache.org/licenses/<br/>\n</p>\n<p><span style=\"font-size: 10pt;\">TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION</spam></p>\n<p><b><span style=\"font-size: 10pt;\">1. Definitions.</span></b> </p>\n<p><span style=\"font-size: 10pt;\">\n    \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.</span></p>\n<p><span style=\"font-size: 10pt;\">\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.</span></p>\n<p><span style=\"font-size: 10pt;\">\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under 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.</span></p>\n<p><span style=\"font-size: 10pt;\">\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.</span></p>\n<p><span style=\"font-size: 10pt;\">\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.</span></p>\n<p><span style=\"font-size: 10pt;\">\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.</span></p>\n<p><span style=\"font-size: 10pt;\">\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).</span></p>\n<p><span style=\"font-size: 10pt;\">\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.</span></p>\n<p><span style=\"font-size: 10pt;\">\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.\"</span></p>\n<p><span style=\"font-size: 10pt;\">\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.</span></p>\n\n<p><b><span style=\"font-size: 10pt;\">2. Grant of Copyright License.</span></b> </p>\n<p><span style=\"font-size: 10pt;\">\nSubject 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.</span></p>\n      \n      \n         <p><b><span style=\"font-size: 10pt;\">3. Grant of Patent License.</span></b><p>\n\n<p><span style=\"font-size: 10pt;\">         \n         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</span></p>\n<p><b><span style=\"font-size: 10pt;\">\n   4. Redistribution. \n      </span></b></p>\n   \n   <p><span style=\"font-size: 10pt;\">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:</span><p>\n<ul>\n<li><span style=\"font-size: 10pt;\">\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and</span><p>\n</li>\n<li><span style=\"font-size: 10pt;\">\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and</span><p>\n</li>\n</li><span style=\"font-size: 10pt;\">\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</span><p>\n</li>\n<li><span style=\"font-size: 10pt;\">\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.</span><p>\n</li>\n</ul>\n</span></p>\n\n<p><span style=\"font-size: 10pt;\">\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</span></p>\n<p><b><span style=\"font-size: 10pt;\">\n   5. Submission of Contributions. \n      </span></b></p>\n   \n   <p><span style=\"font-size: 10pt;\">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</span></p>\n<p><b><span style=\"font-size: 10pt;\">\n   6. Trademarks. \n      </span></b></p>\n   \n   <p><span style=\"font-size: 10pt;\">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</span></p>\n<p><b><span style=\"font-size: 10pt;\">\n   7. Disclaimer of Warranty. \n      </span></b></p>\n   \n   <p><span style=\"font-size: 10pt;\">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</span></p>\n<p><b><span style=\"font-size: 10pt;\">\n   8. Limitation of Liability. \n      </span></b></p>\n   \n   <p><span style=\"font-size: 10pt;\">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</span></p>\n<p><b><span style=\"font-size: 10pt;\">\n   9. Accepting Warranty or Additional Liability. \n   </span></b></p>\n   <p><span style=\"font-size: 10pt;\">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</span></p>\n\n<p><span style=\"font-size: 10pt;\">\n   END OF TERMS AND CONDITIONS\n</span></p>\n\n<p><span style=\"font-size: 10pt;\">\n   APPENDIX: How to apply the Apache License to your work.\n</span></p>\n\n<p><span style=\"font-size: 10pt;\">\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</span></p>\n\n<p><span style=\"font-size: 10pt;\">\n   Copyright [yyyy] [name of copyright owner]\n</span></p>\n\n<p><span style=\"font-size: 10pt;\">\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</span></p>\n\n<p><span style=\"font-size: 10pt;\">\n       http://www.apache.org/licenses/LICENSE-2.0\n</span></p>\n\n<p><span style=\"font-size: 10pt;\">\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</span></p>\n\n</div>\n</body></html>"
  },
  {
    "path": "license_moquette.txt",
    "content": "\r\n                     Copyright 2012-2013 (c) Andrea Selva\r\n\r\n\r\n                                Apache License\r\n                           Version 2.0, January 2004\r\n                        http://www.apache.org/licenses/\r\n\r\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r\n\r\n   1. Definitions.\r\n\r\n      \"License\" shall mean the terms and conditions for use, reproduction,\r\n      and distribution as defined by Sections 1 through 9 of this document.\r\n\r\n      \"Licensor\" shall mean the copyright owner or entity authorized by\r\n      the copyright owner that is granting the License.\r\n\r\n      \"Legal Entity\" shall mean the union of the acting entity and all\r\n      other entities that control, are controlled by, or are under common\r\n      control with that entity. For the purposes of this definition,\r\n      \"control\" means (i) the power, direct or indirect, to cause the\r\n      direction or management of such entity, whether by contract or\r\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r\n      outstanding shares, or (iii) beneficial ownership of such entity.\r\n\r\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\r\n      exercising permissions granted by this License.\r\n\r\n      \"Source\" form shall mean the preferred form for making modifications,\r\n      including but not limited to software source code, documentation\r\n      source, and configuration files.\r\n\r\n      \"Object\" form shall mean any form resulting from mechanical\r\n      transformation or translation of a Source form, including but\r\n      not limited to compiled object code, generated documentation,\r\n      and conversions to other media types.\r\n\r\n      \"Work\" shall mean the work of authorship, whether in Source or\r\n      Object form, made available under the License, as indicated by a\r\n      copyright notice that is included in or attached to the work\r\n      (an example is provided in the Appendix below).\r\n\r\n      \"Derivative Works\" shall mean any work, whether in Source or Object\r\n      form, that is based on (or derived from) the Work and for which the\r\n      editorial revisions, annotations, elaborations, or other modifications\r\n      represent, as a whole, an original work of authorship. For the purposes\r\n      of this License, Derivative Works shall not include works that remain\r\n      separable from, or merely link (or bind by name) to the interfaces of,\r\n      the Work and Derivative Works thereof.\r\n\r\n      \"Contribution\" shall mean any work of authorship, including\r\n      the original version of the Work and any modifications or additions\r\n      to that Work or Derivative Works thereof, that is intentionally\r\n      submitted to Licensor for inclusion in the Work by the copyright owner\r\n      or by an individual or Legal Entity authorized to submit on behalf of\r\n      the copyright owner. For the purposes of this definition, \"submitted\"\r\n      means any form of electronic, verbal, or written communication sent\r\n      to the Licensor or its representatives, including but not limited to\r\n      communication on electronic mailing lists, source code control systems,\r\n      and issue tracking systems that are managed by, or on behalf of, the\r\n      Licensor for the purpose of discussing and improving the Work, but\r\n      excluding communication that is conspicuously marked or otherwise\r\n      designated in writing by the copyright owner as \"Not a Contribution.\"\r\n\r\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\r\n      on behalf of whom a Contribution has been received by Licensor and\r\n      subsequently incorporated within the Work.\r\n\r\n   2. Grant of Copyright License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      copyright license to reproduce, prepare Derivative Works of,\r\n      publicly display, publicly perform, sublicense, and distribute the\r\n      Work and such Derivative Works in Source or Object form.\r\n\r\n   3. Grant of Patent License. Subject to the terms and conditions of\r\n      this License, each Contributor hereby grants to You a perpetual,\r\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r\n      (except as stated in this section) patent license to make, have made,\r\n      use, offer to sell, sell, import, and otherwise transfer the Work,\r\n      where such license applies only to those patent claims licensable\r\n      by such Contributor that are necessarily infringed by their\r\n      Contribution(s) alone or by combination of their Contribution(s)\r\n      with the Work to which such Contribution(s) was submitted. If You\r\n      institute patent litigation against any entity (including a\r\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\r\n      or a Contribution incorporated within the Work constitutes direct\r\n      or contributory patent infringement, then any patent licenses\r\n      granted to You under this License for that Work shall terminate\r\n      as of the date such litigation is filed.\r\n\r\n   4. Redistribution. You may reproduce and distribute copies of the\r\n      Work or Derivative Works thereof in any medium, with or without\r\n      modifications, and in Source or Object form, provided that You\r\n      meet the following conditions:\r\n\r\n      (a) You must give any other recipients of the Work or\r\n          Derivative Works a copy of this License; and\r\n\r\n      (b) You must cause any modified files to carry prominent notices\r\n          stating that You changed the files; and\r\n\r\n      (c) You must retain, in the Source form of any Derivative Works\r\n          that You distribute, all copyright, patent, trademark, and\r\n          attribution notices from the Source form of the Work,\r\n          excluding those notices that do not pertain to any part of\r\n          the Derivative Works; and\r\n\r\n      (d) If the Work includes a \"NOTICE\" text file as part of its\r\n          distribution, then any Derivative Works that You distribute must\r\n          include a readable copy of the attribution notices contained\r\n          within such NOTICE file, excluding those notices that do not\r\n          pertain to any part of the Derivative Works, in at least one\r\n          of the following places: within a NOTICE text file distributed\r\n          as part of the Derivative Works; within the Source form or\r\n          documentation, if provided along with the Derivative Works; or,\r\n          within a display generated by the Derivative Works, if and\r\n          wherever such third-party notices normally appear. The contents\r\n          of the NOTICE file are for informational purposes only and\r\n          do not modify the License. You may add Your own attribution\r\n          notices within Derivative Works that You distribute, alongside\r\n          or as an addendum to the NOTICE text from the Work, provided\r\n          that such additional attribution notices cannot be construed\r\n          as modifying the License.\r\n\r\n      You may add Your own copyright statement to Your modifications and\r\n      may provide additional or different license terms and conditions\r\n      for use, reproduction, or distribution of Your modifications, or\r\n      for any such Derivative Works as a whole, provided Your use,\r\n      reproduction, and distribution of the Work otherwise complies with\r\n      the conditions stated in this License.\r\n\r\n   5. Submission of Contributions. Unless You explicitly state otherwise,\r\n      any Contribution intentionally submitted for inclusion in the Work\r\n      by You to the Licensor shall be under the terms and conditions of\r\n      this License, without any additional terms or conditions.\r\n      Notwithstanding the above, nothing herein shall supersede or modify\r\n      the terms of any separate license agreement you may have executed\r\n      with Licensor regarding such Contributions.\r\n\r\n   6. Trademarks. This License does not grant permission to use the trade\r\n      names, trademarks, service marks, or product names of the Licensor,\r\n      except as required for reasonable and customary use in describing the\r\n      origin of the Work and reproducing the content of the NOTICE file.\r\n\r\n   7. Disclaimer of Warranty. Unless required by applicable law or\r\n      agreed to in writing, Licensor provides the Work (and each\r\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\r\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r\n      implied, including, without limitation, any warranties or conditions\r\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r\n      PARTICULAR PURPOSE. You are solely responsible for determining the\r\n      appropriateness of using or redistributing the Work and assume any\r\n      risks associated with Your exercise of permissions under this License.\r\n\r\n   8. Limitation of Liability. In no event and under no legal theory,\r\n      whether in tort (including negligence), contract, or otherwise,\r\n      unless required by applicable law (such as deliberate and grossly\r\n      negligent acts) or agreed to in writing, shall any Contributor be\r\n      liable to You for damages, including any direct, indirect, special,\r\n      incidental, or consequential damages of any character arising as a\r\n      result of this License or out of the use or inability to use the\r\n      Work (including but not limited to damages for loss of goodwill,\r\n      work stoppage, computer failure or malfunction, or any and all\r\n      other commercial damages or losses), even if such Contributor\r\n      has been advised of the possibility of such damages.\r\n\r\n   9. Accepting Warranty or Additional Liability. While redistributing\r\n      the Work or Derivative Works thereof, You may choose to offer,\r\n      and charge a fee for, acceptance of support, warranty, indemnity,\r\n      or other liability obligations and/or rights consistent with this\r\n      License. However, in accepting such obligations, You may act only\r\n      on Your own behalf and on Your sole responsibility, not on behalf\r\n      of any other Contributor, and only if You agree to indemnify,\r\n      defend, and hold each Contributor harmless for any liability\r\n      incurred by, or claims asserted against, such Contributor by reason\r\n      of your accepting any such warranty or additional liability.\r\n\r\n   END OF TERMS AND CONDITIONS\r\n\r\n   APPENDIX: How to apply the Apache License to your work.\r\n\r\n      To apply the Apache License to your work, attach the following\r\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\r\n      replaced with your own identifying information. (Don't include\r\n      the brackets!)  The text should be enclosed in the appropriate\r\n      comment syntax for the file format. We also recommend that a\r\n      file or class name and description of purpose be included on the\r\n      same \"printed page\" as the copyright notice for easier\r\n      identification within third-party archives.\r\n\r\n   Copyright [yyyy] [name of copyright owner]\r\n\r\n   Licensed under the Apache License, Version 2.0 (the \"License\");\r\n   you may not use this file except in compliance with the License.\r\n   You may obtain a copy of the License at\r\n\r\n       http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n   Unless required by applicable law or agreed to in writing, software\r\n   distributed under the License is distributed on an \"AS IS\" BASIS,\r\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n   See the License for the specific language governing permissions and\r\n   limitations under the License.\r\n"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <netty.version>4.1.68.Final</netty.version>\n        <source.version>1.8</source.version>\n        <target.version>1.8</target.version>\n    </properties>\n\n    <groupId>cn.wildfirechat</groupId>\n    <artifactId>wildfirechat-parent</artifactId>\n\n    <packaging>pom</packaging>\n    <version>1.4.5</version>\n    <name>Wildfire Chat</name>\n    <description>Wildfire Chat Server</description>\n    <inceptionYear>2019</inceptionYear>\n    <url>https://www.wildfirechat.cn</url>\n\n    <licenses>\n        <license>\n            <name>The Apache License, Version 2.0</name>\n            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n        </license>\n        <license>\n            <name>Eclipse Public License - Version 1.0</name>\n            <url>http://www.eclipse.org/org/documents/epl-v10.php</url>\n        </license>\n    </licenses>\n\n\n    <modules>\n        <module>broker</module>\n        <module>common</module>\n        <module>sdk</module>\n        <module>distribution</module>\n    </modules>\n\n    <build>\n    <pluginManagement>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>${source.version}</source>\n                    <target>${target.version}</target>\n                </configuration>\n            </plugin>\n            <plugin>\n              <groupId>org.apache.maven.plugins</groupId>\n              <artifactId>maven-checkstyle-plugin</artifactId>\n              <version>2.17</version>\n              <configuration>\n                  <configLocation>checkstyle.xml</configLocation>\n                  <suppressionsLocation>checkstyle-suppressions.xml</suppressionsLocation>\n                  <!--\n                     <configLocation>/google_checks.xml</configLocation>\n                   -->\n                  <failOnViolation>true</failOnViolation>\n                  <consoleOutput>true</consoleOutput>\n              </configuration>\n              <executions>\n                <execution>\n                  <phase>validate</phase>\n                  <goals>\n                    <goal>check</goal>\n                  </goals>\n                </execution>\n              </executions>\n            </plugin>\n        </plugins>\n    </pluginManagement>    \n    </build>\n\n    <profiles>\n        <profile>\n            <id>release-sign-artifacts</id>\n            <build>\n                <plugins>\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-source-plugin</artifactId>\n                        <executions>\n                            <execution>\n                                <id>attach-sources</id>\n                                <goals>\n                                    <goal>jar</goal>\n                                </goals>\n                            </execution>\n                        </executions>\n                    </plugin>\n\n                    <plugin>\n                        <groupId>org.apache.maven.plugins</groupId>\n                        <artifactId>maven-javadoc-plugin</artifactId>\n                        <executions>\n                            <execution>\n                                <id>attach-javadocs</id>\n                                <goals>\n                                    <goal>jar</goal>\n                                </goals>\n                            </execution>\n                        </executions>\n                    </plugin>\n                </plugins>\n            </build>\n        </profile>\n    </profiles>\n</project>\n"
  },
  {
    "path": "release_note.md",
    "content": "# 升级注意事项\n1. *** 0.42 版本增加了群成员数限制，默认为2000。如果您想修改默认值，可以在升级版本之后，修改t_setting表，把默认的大小改为您期望的。另外修改t_group表，把已经存在的群组max_member_count改成您期望的，然后重启。***\n2. *** 0.46和0.47版本升级到0.48及以后版本时，可能会提示flyway migrate 38错误，请执行 [修复脚本](https://github.com/wildfirechat/server/blob/wildfirechat/flyway_repaire_migrate_38.sql) 进行修复。0.46和0.47版本之外的版本不会出现此问题。***\n3. *** 0.50版本添加了是否允许客户端发送群操作通知的配置。如果您在客户端自定义群通知，需要在服务器端配置允许，没有使用自定义群操作通知的不受影响。***\n4. *** 从0.54之前版本升级到0.54及以后版本时，会提示flyway migrate错误。因为0.54版本删除了sql脚本中默认敏感词的内容，flyway checksum失败。请执行```update flyway_schema_history set checksum = 0 where script = 'V17__add_default_sensitive_word.sql';```来修复。***\n5. *** 从0.59之前的版本升级到之后的版本执行数据库升级时间比较长，请耐心等待提示运行成功，避免中途中断。 ***\n6. *** 0.62/0.63 版本有严重的问题，请使用0.64及以后版本，或者0.61版。 ***\n7. *** 从0.68 版本起添加了pc在线是否默认手机接收推送的开关，默认为开，与以前版本作用相反，请注意兼容（可以关掉与之前保持一致或者升级客户端） ***\n8. *** 从0.78 版本起把MySQL数据库中关键字都改为大小写敏感，另外生成id的方法也做了改变，只生成小写的id，避免出现id重复的问题，建议所有客户都升级 ***\n9. *** 从0.79 版本起把log4j升级到log4j2，因为log4j已经不再维护而且还有已知的漏洞，建议所有客户都升级，升级时注意更新log4j2的配置文件 ***\n10. *** 0.97版本更改了启动脚本```wildfirechat.sh```，如果是升级服务，请注意更新启动脚本。***\n11. *** 1.3.8版本添加了server api发送消息的限制，限制消息体最大内容不能超过64KB，如果升级请注意业务系统发送消息大小。***\n\n# 更新记录\n--------------\nRelease note 1.4.5:\n1. 解决删除用户时保留信息错误问题。\n2. Server API获取用户信息时，可以指定是否获取已删除用户。\n3. 好友关系表添加一个索引。\n4. 支持PC端锁定功能。\n\n--------------\nRelease note 1.4.4:\n1. Server SDK添加mesh相关修改\n2. 添加设置好友Extra的接口。\n3. 解决创建账户时，没有传昵称使用了账户的问题。\n4. 添加获取用户机器人列表的Server API。\n5. 机器人回调消息中加上目标机器人ID。\n6. 机器人获取用户信息添加配置确定能获取哪些字段。\n\n--------------\nRelease note 1.4.3:\n1. 添加内置存储上传文件文件名有效性检查。\n2. 接受好友请求通知的发送者改成接受者发送。\n3. 对象存储添加预留类型供扩展使用。\n4. 同步专业版数据库表格式。\n5. 解决server sdk有轻微内存泄漏的问题。\n\n--------------\nRelease note 1.4.2:\n1. 解决部分情况下Server SDK没有解析出文本消息的问题。\n\n--------------\nRelease note 1.4.1:\n1. 解决移动端和PAD同时存在时推送计数错误问题。\n2. 添加配置，当销毁用户时是否销毁用户信息和用户的消息。\n3. 添加配置，现在搜索用户的次数。\n\n--------------\nRelease note 1.4.0:\n1. 添加对用户IP来源的记录。\n2. 移除无用的plugin，可以在java8环境下编译通过。\n3. Server SDK解决某些Java版本下消息没有注册的问题。\n4. Server SDK解决解析图片缩略图不存在的错误问题。\n5. Server SDK解决发送带引用的消息客户端无法解析的问题。\n\n--------------\nRelease note 1.3.9:\n1. 解决server sdk反复初始化内存泄漏的问题。\n2. 群组支持用户@不在群组中的机器人。\n3. 单聊会话支持@机器人。\n4. 机器人支持回复消息，可以回复单聊或者群聊消息。\n\n--------------\nRelease note 1.3.8:\n1. 添加限制，server api发送消息，限制消息体不能大于64KB。\n2. 添加配置敏感词是否过滤用户信息群组信息昵称等。\n3. 配置文件可以设置不允许使用的用户名字群组名称群名片等。\n4. server api发送消息添加参数，可以以用户权限发送消息。\n5. server api添加群备注和收藏群组接口。\n\n--------------\nRelease note 1.3.7:\n1. 搜索用户可以指定搜索机器人、普通用户或者所有。\n2. 添加群组成员时，允许部分失败。\n3. 解决内置存储上传文件时可能内存泄漏。\n4. 支持客户端上传本地角标，用于推送得到较为精确的角标数字。\n5. 解决机器人回调配置携带发送者用户信息无效的问题。\n\n--------------\nRelease note 1.3.6:\n1. Server API创建频道时，返回频道ID和频道密钥。\n2. 解决外置审核替换内容没有成功的问题。\n3. 修改撤回消息限制，可以运行不限制撤回。\n4. 创建/更新频道接口可以传菜单参数。\n5. Server API支持修改群组类型。\n\n--------------\nRelease note 1.3.5:\n1. 转发消息回调中可以配置带上发送者和目标信息。\n2. Server SDK中添加撤回和删除消息。\n3. Server SDK中添加发送朋友圈接口。\n4. 添加配置是否允许发送消息给被封禁用户。\n5. 音视频通话挂断推送中带上发起消息的ID\n\n--------------\nRelease note 1.3.4:\n1. 优化Server SDK中消息内容的处理方式。\n2. Server SDK中添加注册消息接口，在使用自定义消息时，不需要修改Server SDK源码。\n3. 用户撤回时间配置允许为负数，为负数时可以任意时间撤回。\n4. Server SDK添加超时参数。\n5. 解决当分段拉取消息时，可能丢失消息的问题。\n\n--------------\nRelease note 1.3.3:\n1. 转移群组时检查新群主是否在群中。\n2. 机器人API添加定向消息接口。\n\n--------------\nRelease note 1.3.2:\n1. 机器人Server SDK添加朋友圈相关接口。\n2. Server API添加批量获取用户接口。\n3. 解决聊天室定向消息无效的问题。\n4. 添加配置，可以在禁止私聊时添加例外聊天线路。\n\n--------------\nRelease note 1.3.1:\n1. 透传消息去掉消息ID，减少消息传输大小。\n2. 修改添加好友策略，可以设置禁止加自己好友。\n3. Server API创建群组时，检查是否设置operator。\n4. SDK添加删除广播和组播消息接口\n\n--------------\nRelease note 1.3.0:\n1. 推送信息中添加republish参数，用于标识消息是重新发布的。\n2. 添加好友请求限频功能，在IM服务配置中可以配置每天限制添加的好友数。\n3. 添加配置，是否允许用户发送消息给被拉黑的用户。\n4. 添加鸿蒙回调地址。\n5. 创建群组或者添加群组成员时，群组成员的Extra会放到通知消息的extra中，这样便于业务处理通知消息。\n\n--------------\nRelease note 1.2.9:\n1. 解决server api获取群组信息不全的问题。\n2. 添加配置使用uuid作为用户群组等ID。\n\n--------------\nRelease note 1.2.8:\n1. server api获取被封禁用户时，过滤掉正常用户。\n2. 解决群组标记删除错误。\n3. SDK中添加发送消息的示例。\n4. 群解散后撤回群中的消息应该失败。\n5. 解决某些时候http请求返回信息无法读取问题。\n\n--------------\nRelease note 1.2.7:\n1. 解决搜索频道时某些类型的频道无法被搜索的问题。\n2. 添加频道回调新特性，方便使用。\n3. 解决机器人API修改机器人用户信息客户端没有更新的问题。\n4. Server SDK中关于频道的接口放到ChannelAdmin中。\n5. 添加Mesh功能的SDK。\n\n--------------\nRelease note 1.2.6:\n1. 群主强制被退群时（销毁账号/server api强制退群），调整新群主选择，群管理优先，先加入群组优先。\n2. 拉取远程消息时，过滤掉可能重复的消息。\n3. 退群时添加是否保留消息的参数，可以退群后保留原有消息。\n4. 如果不在群组中，当获取群组信息时不更新数据。\n\n--------------\nRelease note 1.2.5:\n1. Server API添加通过邮箱获取用户信息的接口。\n2. 支持群组标记删除功能。\n3. 添加配置，可以设置在静音时强制推送指定类型消息。\n4. 支持用户设置添加好友是否验证功能\n\n--------------\nRelease note 1.2.4:\n1. 去掉用户的默认密码。\n2. 去掉频道和机器人的默认头像。\n3. 修改在线状态回调数据，返回此用户的所有端状态。\n\n--------------\nRelease note 1.2.3:\n1. 同步专业版IM服务server SDK。\n2. 添加对鸿蒙平台的支持。\n3. 解决server端音视频SDK信令支持问题。\n4. 升级部分依赖，解决漏洞问题\n\n--------------\nRelease note 1.2.2:\n1. 解决搜索特殊字符时的转义问题。\n2. SDK添加流式消息。\n3. 添加配置，是否禁止拉陌生人入群。\n4. 放被拉黑时禁止被拉入群\n5. 群组信息变更回调时加上群组信息\n6. 机器人sdk添加撤回和更新消息接口\n\n--------------\nRelease note 1.2.1:\n1. 添加获取在线用户功能。\n2. 添加获取用户连接session信息的功能。\n3. 优化按照用户id搜索用户的逻辑。\n4. 解决广播消息没有发给未登录用户的问题。\n\n--------------\nRelease note 1.2.0:\n1. 添加配置开关，可以关掉api/version检查接口。\n2. Server SDK会议事件中添加时间戳。\n3. 禁止私聊时，如果一方在允许私聊列表中，允许私聊。\n4. 解决某些特殊情况下获取网卡信息失败导致启动失败的问题。\n5. 支持按照用户ID来搜索用户。\n6. 添加获取某个用户是否在聊天室的接口。\n7. 优化多端加入聊天室的处理。\n\n--------------\nRelease note 1.1.9:\n1. 解决服务器时间误差太大引起的问题。\n2. 添加推送过期配置。\n3. 支持发送好友请求后5分钟之内再次发送。\n4. Server API支持根据群成员类型获取用户群列表。\n5. 添加配置，是否允许群主和群管理员无限制撤回自己的消息。\n\n--------------\nRelease note 1.1.8:\n1. 解决可以把群主设置为管理员的问题。\n2. 发送好友请求之后5分钟内可以再次发送。\n3. 解决撤回消息中原消息二进制内容格式错误问题。\n\n--------------\nRelease note 1.1.7:\n1. 优化用户搜索功能。\n2. 推送消息中使用群备注。\n3. 推送消息中添加发送者和目标头像。\n4. 优化撤回消息流程。\n\n--------------\nRelease note 1.1.6:\n1. 支持用户设置查找自己的方法。\n2. 解决获取用户信息返回type无效的问题。\n3. 添加用户获取频道的功能。\n\n--------------\nRelease note 1.1.5:\n1. 添加获取所有用户的Server API。\n2. 解决添加好友时没有处理黑名单的问题。\n\n--------------\nRelease note 1.1.4:\n1. 添加PC客户端多端登录互踢时没有更新pc在线状态问题。\n2. 添加支持使用AES256加密。\n3. Server API添加获取单个群成员的接口。\n4. 添加配置，添加机器人为好友时是否自动接受。\n\n--------------\nRelease note 1.1.3:\n1. 添加服务器和客户端时间检查功能。\n2. 解决用户被block后session失效的问题。\n3. 添加消息撤回回调。\n4. 优化群组撤回逻辑。\n5. 解决用户离开群组后还能修改群昵称的问题。\n6. 修改server api修改好友关系回调数据错误问题。\n7. 同步超级群组数据库和数据。\n\n--------------\nRelease note 1.1.2:\n1. 会议SDK添加查询会议是否存在的接口\n2. 单聊会话定向消息分发包含发送者\n\n--------------\nRelease note 1.1.1:\n1. 当用户获取群组信息，可以根据返回信息判断是否在群中。\n2. 搜索用户时，过滤掉已删除用户\n3. 支持单聊消息的定向消息\n4. 解决关闭roaming，且message.compensate_time_limit配置为-1时，首次消息无法同步的问题\n5. 解决禁止客户端群操作flag 解析错误\n\n--------------\nRelease note 1.1:\n1. Channel API添加检查用户是否订阅接口\n2. Server API发送消息时添加检查对象是否存在\n3. Channel API添加修改频道菜单接口\n4. 内置对象存储的优化\n\n--------------\nRelease note 1.0:\n1. SDK检查工具添加help命令\n2. 去掉短连接端口被网络爬虫扫描输出的异常日志\n3. API支持创建组织群\n4. 添加配置禁止客户端进行某些群操作\n5. 解决route请求时可能不能正确携带推送类型的问题\n6. 会议成员离开加上离开原因\n7. 添加停止程序的命令\n8. 添加RTP Forward的API\n\n--------------\nRelease note 0.99:\n1. API获取用户信息时，过滤掉已经删除用户。\n2. 消息转发功能支持设置include/exclude功能，支持按区间过滤。\n3. 添加新的群组类型：组织群。组织群适用于公司部门群场景。\n4. 内置对象存储支持绝对路径和相对路径配置\n5. 当开启禁止陌生人聊天时，可以添加例外人员\n6. 解决user setting并发问题\n7. 添加可选的android平台签名验证功能。\n\n--------------\nRelease note 0.98:\n1. 解决linux多端登录错误问题\n2. 添加获取用户群组和共同群组功能\n3. 解决windows下脚本编码错误问题\n\n--------------\nRelease note 0.97:\n1. 升级部分依赖库到最新版本\n2. 添加名片消息默认推送信息\n3. 添加deb和rpm格式软件包\n\n--------------\nRelease note 0.96:\n1. 文章消息添加摘要字段\n2. 单聊消息支持server api只发送给其中一方\n3. Server api添加会议录制/停止录制接口\n\n--------------\nRelease note 0.95:\n1. 添加按照用户删除会话接口\n2. 升级netty版本为4.1.68.Final\n3. 公众号文章添加摘要字段\n\n--------------\nRelease note 0.94:\n1. Server SDK添加删除会话接口\n2. 解决内置对象存储某些类型文件返回content-type错误问题\n3. 添加server api检查是否订阅频道接口\n4. 添加超频检查忽略信令\n5. gson单例化，且关掉html转义。\n\n--------------\nRelease note 0.93:\n1. Server API添加订阅频道功能\n2. 短链接端口添加HEAD方法处理\n3. Server SDK的HTTP Client调整部分参数，解决出现连接错误问题\n4. 添加敏感词回调功能\n\n--------------\nRelease note 0.92:\n1. SDK部分POJO对象添加无参数构造函数解决某些反序列化工具失败问题。\n2. 频道只有在auto属性为1时，才会回调函数及订阅事件。\n3. 添加配置，在关闭消息漫游时，客户端首次登录同步多久时间之内的消息。\n4. 频道添加菜单属性。\n\n---------------\nRelease note 0.91:\n1. 创建群组时检查群组类型的有效性。\n2. 添加配置消息回调时是否带上客户端信息。\n3. 添加群组成员时，检查是否已经在群组中。\n\n---------------\nRelease note 0.90:\n1. mysql-connector-java版本升级到8.0.28\n2. 配置文件中去掉绑定IP的配置，防止误操作\n3. 解决客户端触发限频多调用一次callback的错误。\n\n---------------\nRelease note 0.89:\n1. gson依赖库升级到2.8.9\n2. log4j升级到2.17.2\n3. 解决SDK部分响应反序列化失败的问题\n4. 添加配置允许PC多端\n\n---------------\nRelease note 0.88:\n1. 添加部分数据库表的索引。\n2. 优化频道订阅关系的缓存处理。\n3. 添加支持开放平台的接口。\n4. 机器人和频道回调消息中添加缺失信息。\n5. 频道automic状态为1时，都不发送消息给owner。\n6. 机器人api添加获取机器人信息的接口。\n7. 解决server api撤回单聊消息时发送方无法撤回的问题\n\n---------------\nRelease note 0.87:\n1. 优化pc在线状态逻辑。\n2. 添加配置当删除用户时使用的用户昵称。\n3. 添加获取单条消息接口。\n\n---------------\nRelease note 0.86:\n1. Server SDK获取在线用户结果的变量改成公开\n\n---------------\nRelease note 0.85:\n1. 消息只能撤回一次，不能重复撤回。\n3. gzip压缩避免内存泄漏\n\n---------------\nRelease note 0.84:\n1. 定向消息，如果有多于一个收件人，只保存第一个收件人，避免定向消息被远程消息拉取下来。\n3. 内置文件存储，是否内存避免内存泄漏。\n\n---------------\nRelease note 0.83:\n1. 解决多端登陆时，处理好友请求状态同步问题\n2. SDK会议接口中添加permanent参数，可以创建永久保存会议。\n\n---------------\nRelease note 0.82:\n1. 修正PC在线状态逻辑错误问题\n2. 销毁用户时，清理所有信息\n4. SDK中添加更新消息的接口（仅专业版支持）\n5. SDK中添加获取在线用户数据（仅专业版支持）\n\n---------------\nRelease note 0.81:\n1. 修正PC在线状态某些特殊情况下错误问题\n2. 写入用户信息关系表时带上会话信息\n\n---------------\nRelease note 0.80:\n1. 全局频道或者可以给非订阅用户发送消息的频道允许非订阅用户回复消息\n2. Server API获取群组成员带上群组成员加入时间\n4. 支持平板端接入\n5. 解决有时PC在线状态错误问题\n6. log4j2升级到2.17.1\n\n---------------\nRelease note 0.79:\n1. 频道API发送消息时，如果automic则不发送给频道主\n2. 修改UserSetting表的key字段长度\n3. 敏感词过滤跳过链接，链接内的词语不过滤敏感词\n4. 销毁聊天室时，清理相关数据\n6. 加入聊天室时判断是否聊天室已经清理\n7. 升级log4j到log4j2\n\n---------------\nRelease note 0.78:\n1. 添加是否允许机器人自定义群通知的配置\n2. 修正禁止存储searchablecontent时的错误问题\n3. 解决API修改群组或用户为空时的异常问题\n4. 当用户修改自己信息时，通知其他的更新自己的信息\n5. MySQL数据字段中的关键字改为大小写敏感\n7. 使用新的id生成方法，生成9为数字小写字母组成的id。\n\n---------------\nRelease note 0.77:\n1. Server API添加获取频道信息，销毁频道，销毁机器人功能。\n2. 解决频道API发送中文乱码问题。\n3. 解决频道拉取远程消息错乱问题。\n4. 添加频道无密钥的错误码。\n5. 解决频道和机器人API高压力下错乱问题。\n\n---------------\nRelease note 0.76:\n1. 为聊天室单独添加拉取远程消息开关。\n2. 获取远程消息支持过滤消息类型。\n3. 推送、消息、回调等事件HTTP请求失败打印提示信息。\n\n---------------\nRelease note 0.75:\n1. 修正有时欢迎语排序乱序问题。\n2. 机器人禁止获取IM token。\n\n---------------\nRelease note 0.74:\n1. 发送好友请求时，如果已经是好友了，返回已经是好友的错误码\n2. 修正通过server api修改用户昵称没有通知客户端的问题\n3. 添加限频配置项\n\n---------------\nRelease note 0.73:\n1. 优化客户端断开连接功。\n2. 解决双方同时添加好友，后接受的失败的问题。\n\n---------------\nRelease note 0.72:\n1. 添加提醒消息回调\n2. 优化客户端断开连接功能\n3. 支持客户端lite模式\n\n---------------\nRelease note 0.71:\n1. 添加多端登录被踢下线的错误码\n2. 添加VOIP免打扰功能\n3. 消息撤回推送功能\n4. 推送只有pushData，没有pushContent也要推送\n\n---------------\nRelease note 0.70:\n1. 修改敏感词过滤问题\n2. 添加修改好友附加信息的server api\n\n---------------\nRelease note 0.69:\n1. 完善会议API\n2. 解决配置文件中特殊字符的问题\n3. 添加简单的健康检查API\n\n---------------\nRelease note 0.68:\n1. 去掉脚本中GC日志输出，减少无效日志。\n2. 添加配置是否加密存储消息。\n3. 当接受好友请求时，如果请求原因为空，不发送消息。\n4. 添加开关，当pc/web在线时移动端默认是否接收通知。\n5. 解决文件不存在时的异常日志。\n\n---------------\nRelease note 0.67:\n1. Server API发送好友强制参数错误问题\n2. 添加群组成员附加信息字段\n3. 添加配置，允许加入聊天室不存在时自动创建\n4. 解决Server API创建群组，部分参数无效问题\n5. Server SDK链接复用问题修正\n\n---------------\nRelease note 0.66:\n1. Server SDK支持多个机器人账户\n\n---------------\nRelease note 0.65:\n1. 添加分段更新好友/好友请求/用户设置功能，防止相关数据太大无法更新下来\n2. 同步Server SDK中关于会议的接口\n3. 修正Server API设置好友请求被限制的问题\n\n---------------\nRelease note 0.64:\n1. 修正0.62版本重构引入的短链接错乱问题\n2. 添加server api获取群组信息缺失字段\n3. 添加配置项，可以为内置存储配置远程服务地址\n\n---------------\nRelease note 0.63:\n1. 实现频道权限功能\n2. 配置文件中打开默认开启新好友欢迎语模式\n3. 客户端更新用户设置时，不用再通知当前端\n4. 群成员和好友请求中添加Extra字段\n\n---------------\nRelease note 0.62:\n1. 修改限频逻辑，server API，机器人api，频道api和客户端的限频要分开，避免server api超频导致客户端无法使用。\n2. 添加关闭群主/群管理撤回用户权限的开关。\n3. 对部分代码进行了重构。\n\n---------------\nRelease note 0.61:\n1. 升级缓存Hazelcast版本\n\n---------------\nRelease note 0.60:\n1. 解决server api修改群组信息失败问题\n\n---------------\nRelease note 0.59:\n1. 当server api未签名时，返回未签名的错误码\n2. 当群成员离开群后再次加入群时，修改群成员createTime为最后一次加入时间\n3. 解决自定义群组操作通知无效的问题\n4. 群组修改extra时，发送通知给客户端\n5. server api修改用户信息时添加修改name属性能力\n6. 为user messages表添加会话信息及索引等\n8. 内置测试存储文件上限提升到200MB\n\n---------------\nRelease note 0.58:\n1. 多人音视频添加成员也需要推送消息\n2. 添加禁言时允许发送的消息类型配置\n3. 添加频道相关api\n\n---------------\nRelease note 0.57:\n1. 修正某些情况下群组成员变更无法同步到客户端的问题\n\n---------------\nRelease note 0.56:\n1. 修正同一个设备登录多个用户的问题\n2. 优化启动脚本，可以在bin目录下执行\n\n---------------\nRelease note 0.55\n1. 添加更新用户api接口\n\n---------------\nRelease note 0.54:\n1. 添加对接第三方敏感词处理接口\n2. 添加消息转发类型过滤参数\n3. 去掉对客户端最大版本号的限制，可以兼容未来版本客户端\n4. 去掉默认敏感词\n\n---------------\nRelease note 0.53:\n1. 修正当敏感词策略为忽略时敏感词消息会从历史消息功能中拉取的问题\n2. 修正创建群组时，如果没有把owner加入到群成员列表中，服务器自动加入群成员列表，但count计数时没有加入的问题\n3. 添加获取两个用户之间用户关系的接口\n4. 解决某些情况下群组成员计数不准确的问题\n\n---------------\nRelease note 0.52:\n1. 添加配置是否同步用户信息中敏感信息到客户端\n2. SDK添加会话置顶功能\n3. 屏蔽掉日志中消息内容的打印，防止日志泄漏聊天内容\n4. 添加机器人进行群操作的功能\n5. 添加机器人更改机器人回调地址的接口\n6. 创建群组时，如果群主不在成员列表中自动加入群主\n8. 禁止客户端直接修改自己的电话号码，只能通过server api修改自己的电话号码\n9. 推送接听信息到客户端\n10. 优化客户端被踢下线的逻辑\n11. 内置存储下载时带上content-type字段\n12. 添加历史消息自动清除功能，3年以上的历史消息自动删除\n\n---------------\nRelease note 0.51:\n1. 修改群成员昵称时，发送通知消息\n2. 添加异常报警功能\n3. 修正清除客户端清除掉数据库，无法获取自己发送消息的问题\n4. 解决某些特殊情况下，用户session错误问题\n5. 优化多端客户端被踢下线或者pc被手机踢下线的功能\n\n---------------\nRelease note 0.50:\n1. 解决分页查找用户或者频道，查找翻页错误问题\n2. 添加是否允许客户端发送群操作通知的开关\n3. 添加禁止客户端发送消息类型的配置，可以配置禁止客户端发送特定类型消息\n4. 添加设置群成员昵称接口\n5. 添加配置，当退群或者踢人时是否发送显式通知消息\n\n---------------\nRelease note 0.48\n1. 推送数据中加上用户id\n2. server sdk发送消息接口添加定向用户参数\n3. 状态消息改为可以同步到发送者其它端\n4. 支持jdk15\n5. 添加撤回组播和广播消息接口\n6. 解决用户关系不存在时无法备注的问题\n\n---------------\nRelease note 0.48\n1. 同步专业版数据库\n\n---------------\nRelease note 0.47:\n1. 添加按照时间段免打扰功能\n2. 解决服务器压力过大时消息id可能重复问题\n3. 解决当拉取历史消息时，如果中间几个月没有发过消息无法拉取消息问题\n4. 移除掉无用的fastjson库，避免系统安全警告\n5. 添加群组/用户信息/频道信息变更通知\n\n---------------\nRelease note 0.46:\n1. Server api获取用户好友以好友状态时间排序\n2. 增加Server api发送好友请求的功能\n3. 解决server api删除好友时没有发送通知的问题\n4. 添加PC在线时是否移动端推送的开关\n5. 在频道或机器人没有密钥的情况下禁止使用api\n6. 添加默认文件助手用户\n7. 支持群主或群管理修改群成员昵称的功能\n\n---------------\nRelease note 0.45:\n1. 修正golang server api请求兼容问题。\n2. 修改两个用户互相发送好友请求时，丢失其中一条的问题。\n3. 解决server api删除好友失败的问题。\n\n---------------\nRelease note 0.44:\n1. 解决server api修改群成员昵称不生效的问题\n2. 添加服务器端允许撤回时间最长限制，仅对普通用户有效，系统管理员/server api/群管理员可以任何时候撤回消息\n3. 获取群成员接口检查权限，不在群组中成员无法获取群成员。\n4. 撤回消息的extra中添加更多原始消息内容\n5. 用户在线状态回调接口添加包名\n6. 创建群组时，按照请求列表顺序对成员排序\n7. 修正server SDK中的错误测试例\n9. Server SDK中添加对专业版白名单的支持\n10. 修正server api中设置好友状态不能实时同步到客户端的问题\n11. 修正客户端创建群组时，群主的群成员状态错误问题\n\n---------------\nRelease note 0.43:\n1. 修改撤回消息，extra信息填写错误问题\n2. 修正黑名单设置后无法取消问题\n3. 推送信息添加push_data字段\n4. 消息过期时间问题修正\n5. server api创建群组时，添加更多的可选参数\n6. 修正推送数据中计数不准确问题\n\n> *** 0.42 版本增加了群成员数限制，默认为2000。如果您想修改默认值，可以在升级版本之后，修改t_setting表，把默认的大小改为您期望的。另外修改t_group表，把已经存在的群组max_member_count改成您期望的，然后重启。***\n\n--------------\n\nRelease note 0.42:\n1. 当接受好友请求时，如果已经时好友，返回已经是好友的错误码\n2. 解决SDK中修改群信息缺少自定义通知内容的问题\n3. Server api获取群成员过滤掉已经删除成员信息\n4. SDK增加群内禁言功能（仅专业版支持）\n5. 转发消息带上消息id和时间戳\n6. 对拉黑server api添加参数校验\n7. 群成员添加加入时间属性\n8. 音视频电脑挂掉消息不增加未读消息计数\n9. 添加对群成员最大限制控制，默认为2000\n10. 普通成员可以修改群extra属性。\n12. 修改使用server api操作群时通知错误\n> *** 0.42 版本增加了群成员数限制，默认为2000。如果您想修改默认值，可以在升级版本之后，修改t_setting表，把默认的大小改为您期望的。另外修改t_group表，把已经存在的群组max_member_count改成您期望的，然后重启。***\n\n--------------\n\nRelease note 0.41:\n1. 添加手机控制PC下线功能\n2. 添加是否保存searchable_content字段的配置\n3. 增加移动端退出不清除session且不推送消息操作（现在移动端退出有3个可选参数，断开连接有消息就推送/断开连接清掉服务器session/断开连接不推送且保留session）\n4. SDK添加对物联网设备的支持（物联网接入功能仅专业版有效)\n\n--------------\n\nRelease note 0.40:\n1. 修正拒绝好友错误问题。\n2. 添加聊天室API。\n3. 添加禁止用户搜索和禁止添加好友的配置。\n4. 升级mysql connector到8.0.19版本。\n5. 添加PC在线状态通知。\n6. 在撤回消息中加上被撤回的内容。\n7. 修改设置黑名单失败的问题。\n8. 添加sticker bucket的支持。\n\n--------------\n\nRelease note 0.39:\n1. 修正群内定向消息发送错误问题\n2. 添加好友成功多语言处理\n3. 修正拒绝好友请求的错误问题\n4. 修正内置测试文件服务器部分错误问题\n5. 添加机器人根据电话号码或用户名查询用户接口\n6. 修正Server SDK中的用户关系错误问题\n7. 修改获取用户在线状态错误问题\n8. 修正用户信息中社交字段无法更新问题\n9. 在好友关系中添加extra字段\n10. 给token添加过期时间配置\n11. 添加获取聊天室成员的api\n13. 修改被封禁用户连接失败的错误码\n14. 添加好友请求推送\n\n--------------\n\nRelease note 0.38:\n1. 添加好友请求过期时间配置，可以配置重复发起好友请求时间\n2. 修正黑名单策略为1时发送消息仍失败的错误\n3. 增加sdk中聊天室创建接口，增加sdk聊天室相关测试代码\n4. 修改创建用户时不能指定用户类型的错误\n5. 增加日志默认大小\n6. 修改频道发送消息给指定用户错误问题\n7. 添加检查token是否正确的api\n8.  修正频道创建错误，修正频道发送消息错误\n\n---------------\nRelease note 0.37-1:\n1. 修复聊天室逻辑错误\n\n---------------\nRelease note 0.37\n1. 修正sdk中好友相关接口的错误。\n2. 添加是否运行陌生人聊天的配置。\n3. 增加获取备注的api。\n4. 增加用户在线状态回调功能。\n5. 优化聊天室逻辑，添加用户超时退出聊天室配置和是否发消息自动加入配置。\n6. 禁止发送消息给被封禁用户。\n7. 判断是否devicetoken重复时，加上包名条件。\n8. 添加好友请求相关时间配置。\n9. 添加频道SDK\n\n---------------\nRelease note 0.36\n1. 修正某些特殊情况下群组操作不同步的问题\n2. 优化用户的session管理\n\n---------------\nRelease note 0.35\n1. 修正0.34版本引入的无法拉取消息的严重问题\n2. 修正单条消息大于512K时无法收取消息问题\n3. 修改群主被添加进群状态错误问题\n4. 添加新的搜索类型，新增加按照账户或按照电话号码搜索\n\n---------------\nRelease note 0.34\n1.，添加销毁用户server接口和功能\n2，添加获取用户群组列表接口和功能\n3，添加用户已删除状态\n4，解决IM服务调用推送服务内存泄漏问题\n5，添加服务器为用户缓存消息条数配置\n\n\n--------------\nRelease note 0.33\n\n1. 优化用户session逻辑\n\n--------------\n\nRelease note 0.32:\n1. 排除重复的device token\n2. 添加关闭多端功能。\n\n--------------\n\nRelease note 0.31:\n1，解决了黑名单的同步的问题\n2，解决了黑名单发送消息成功的问题\n\n--------------\n\nRelease note 0.30:\n1，重构了黑名单功能，好友关系和黑名单关系分开\n2，添加敏感词后立即生效\n3，转让群主后，群成员状态问题修复\n4，修改离线消息包大小，从1M改为512K\n"
  },
  {
    "path": "sdk/README.md",
    "content": "# 野火IM Server Java SDK\n\n野火IM Server Java SDK 是野火IM服务器的官方 Java 语言 SDK，提供了完整的 Admin API、Robot API 和 Channel API 接口封装。\n\n## 功能特性\n\n- **用户管理**：创建用户、获取用户信息、更新用户信息、封禁/解封用户等\n- **群组管理**：创建群组、添加/移除成员、转让群主、设置管理员等\n- **消息管理**：发送消息、广播消息、撤回消息、删除消息等\n- **好友关系**：添加好友、删除好友、获取好友列表、设置黑名单等\n- **聊天室管理**：创建聊天室、获取聊天室信息、销毁聊天室等\n- **频道管理**：创建频道、订阅/取消订阅、发送频道消息等\n- **机器人服务**：机器人消息收发、用户信息查询、群组管理等\n- **会议管理**：创建会议、查询会议信息、管理参会者等（高级音视频功能）\n- **朋友圈功能**：发布动态、评论、点赞等（需启用朋友圈功能）\n- **敏感词管理**：添加/删除敏感词、检查敏感词等\n\n## 安装\n\n### Maven 依赖\n\n```xml\n<dependencies>\n    <!-- 必需依赖 -->\n    <dependency>\n        <groupId>com.google.code.gson</groupId>\n        <artifactId>gson</artifactId>\n        <version>2.8.9</version>\n    </dependency>\n    <dependency>\n        <groupId>commons-httpclient</groupId>\n        <artifactId>commons-httpclient</artifactId>\n        <version>3.1</version>\n    </dependency>\n    <dependency>\n        <groupId>org.apache.httpcomponents</groupId>\n        <artifactId>httpclient</artifactId>\n        <version>4.5.13</version>\n    </dependency>\n    <dependency>\n        <groupId>commons-codec</groupId>\n        <artifactId>commons-codec</artifactId>\n        <version>1.15</version>\n    </dependency>\n    <dependency>\n        <groupId>com.google.protobuf</groupId>\n        <artifactId>protobuf-java</artifactId>\n        <version>2.5.0</version>\n    </dependency>\n    <dependency>\n        <groupId>com.googlecode.json-simple</groupId>\n        <artifactId>json-simple</artifactId>\n        <version>1.1.1</version>\n    </dependency>\n    \n    <!-- SDK JAR (本地路径根据实际情况修改) -->\n    <dependency>\n        <groupId>cn.wildfirechat</groupId>\n        <artifactId>sdk</artifactId>\n        <version>1.2.2</version>\n        <scope>system</scope>\n        <systemPath>${project.basedir}/lib/sdk.jar</systemPath>\n    </dependency>\n    <dependency>\n        <groupId>cn.wildfirechat</groupId>\n        <artifactId>common</artifactId>\n        <version>1.2.2</version>\n        <scope>system</scope>\n        <systemPath>${project.basedir}/lib/common.jar</systemPath>\n    </dependency>\n</dependencies>\n\n<!-- Spring Boot 项目需要添加 includeSystemScope -->\n<build>\n    <plugins>\n        <plugin>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-maven-plugin</artifactId>\n            <configuration>\n                <includeSystemScope>true</includeSystemScope>\n            </configuration>\n        </plugin>\n    </plugins>\n</build>\n```\n\n### SDK 获取\n\n1. 从源码编译：本项目位于 `server/sdk` 目录\n2. 从发布包获取：在 release 包的 `server_sdk` 目录中\n\n## 快速开始\n\n### Admin 管理 API\n\n```java\nimport cn.wildfirechat.sdk.AdminConfig;\nimport cn.wildfirechat.sdk.UserAdmin;\nimport cn.wildfirechat.sdk.MessageAdmin;\nimport cn.wildfirechat.pojos.InputOutputUserInfo;\nimport cn.wildfirechat.pojos.Conversation;\nimport cn.wildfirechat.sdk.messagecontent.TextMessageContent;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.sdk.model.IMResult;\n\npublic class QuickStart {\n    public static void main(String[] args) throws Exception {\n        // 初始化配置\n        AdminConfig.initAdmin(\"http://localhost:18080\", \"123456\");\n        \n        // 创建用户\n        InputOutputUserInfo user = new InputOutputUserInfo();\n        user.setUserId(\"user1\");\n        user.setName(\"user1\");\n        user.setDisplayName(\"Test User\");\n        user.setMobile(\"13900000000\");\n        \n        IMResult<OutputCreateUser> result = UserAdmin.createUser(user);\n        if (result.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"创建用户成功: \" + result.getResult().getUserId());\n        }\n        \n        // 获取用户 Token\n        IMResult<OutputGetIMTokenData> tokenResult = UserAdmin.getUserToken(\n            \"user1\", \n            \"client1\", \n            ProtoConstants.Platform.Platform_Android\n        );\n        if (tokenResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Token: \" + tokenResult.getResult().getToken());\n        }\n        \n        // 发送消息\n        Conversation conversation = new Conversation();\n        conversation.setType(ProtoConstants.ConversationType.ConversationType_Private);\n        conversation.setTarget(\"user2\");\n        conversation.setLine(0);\n        \n        TextMessageContent content = new TextMessageContent(\"Hello, World!\");\n        MessagePayload payload = content.encode();\n        \n        IMResult<SendMessageResult> msgResult = MessageAdmin.sendMessage(\"user1\", conversation, payload);\n        if (msgResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"消息发送成功，ID: \" + msgResult.getResult().getMessageUid());\n        }\n    }\n}\n```\n\n### Robot 机器人服务\n\n```java\nimport cn.wildfirechat.sdk.RobotService;\nimport cn.wildfirechat.sdk.messagecontent.TextMessageContent;\n\npublic class RobotExample {\n    public static void main(String[] args) throws Exception {\n        // 初始化机器人服务\n        RobotService robot = new RobotService(\"http://localhost\", \"robot1\", \"123456\");\n        \n        // 获取机器人信息\n        IMResult<OutputRobot> profile = robot.getProfile();\n        if (profile.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"机器人名称: \" + profile.getResult().getDisplayName());\n        }\n        \n        // 发送消息给用户\n        TextMessageContent content = new TextMessageContent(\"Hello from robot!\");\n        IMResult<SendMessageResult> result = robot.sendMessage(\"user1\", content);\n        if (result.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"机器人消息发送成功\");\n        }\n        \n        // 获取用户信息\n        IMResult<OutputUserInfo> userInfo = robot.getUserInfo(\"user1\");\n        if (userInfo.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"用户显示名: \" + userInfo.getResult().getDisplayName());\n        }\n    }\n}\n```\n\n### Channel 频道服务\n\n```java\nimport cn.wildfirechat.sdk.ChannelServiceApi;\nimport cn.wildfirechat.sdk.messagecontent.TextMessageContent;\n\npublic class ChannelExample {\n    public static void main(String[] args) throws Exception {\n        // 初始化频道服务\n        ChannelServiceApi channel = new ChannelServiceApi(\"http://localhost\", \"channel1\", \"secret\");\n        \n        // 发送广播消息给订阅者\n        TextMessageContent content = new TextMessageContent(\"Channel broadcast message\");\n        IMResult<SendMessageResult> result = channel.broadcastMessage(content);\n        if (result.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"频道广播消息发送成功\");\n        }\n        \n        // 用户订阅频道\n        IMResult<Void> subscribeResult = channel.subscribe(\"user1\");\n        if (subscribeResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"订阅成功\");\n        }\n        \n        // 获取频道订阅者（商业版功能）\n        IMResult<OutputStringList> subscribers = channel.getSubscriberList();\n        if (subscribers.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"订阅者数量: \" + subscribers.getResult().getList().size());\n        }\n    }\n}\n```\n\n## 运行测试\n\nSDK 提供了完整的测试示例 `Main.java`：\n\n```bash\n# 编译\nmvn compile\n\n# 运行测试（使用默认配置）\nmvn exec:java -Dexec.mainClass=\"cn.wildfirechat.sdk.Main\"\n\n# 运行测试（自定义配置）\nmvn exec:java -Dexec.mainClass=\"cn.wildfirechat.sdk.Main\" \\\n    -Dexec.args=\"http://your-server:18080 your-secret http://your-server false false\"\n```\n\n### 命令行参数\n\n```\nUsage: java -jar sdk.jar adminUrl adminSecret imUrl commercialServer advanceVoip\n\n参数说明:\n  adminUrl         - 管理API地址，如 http://localhost:18080\n  adminSecret      - 管理员密钥\n  imUrl            - IM服务地址（机器人/频道使用），如 http://localhost\n  commercialServer - 是否为商业版服务器 (true/false)\n  advanceVoip      - 是否启用高级音视频功能 (true/false)\n```\n\n## 项目结构\n\n```\nsdk/\n├── src/main/java/cn/wildfirechat/\n│   ├── sdk/\n│   │   ├── AdminConfig.java          # 配置类\n│   │   ├── UserAdmin.java            # 用户管理\n│   │   ├── GroupAdmin.java           # 群组管理\n│   │   ├── MessageAdmin.java         # 消息管理\n│   │   ├── RelationAdmin.java        # 好友关系管理\n│   │   ├── ChatroomAdmin.java        # 聊天室管理\n│   │   ├── ChannelAdmin.java         # 频道管理\n│   │   ├── GeneralAdmin.java         # 通用管理\n│   │   ├── SensitiveAdmin.java       # 敏感词管理\n│   │   ├── ConferenceAdmin.java      # 会议管理\n│   │   ├── MomentsAdmin.java         # 朋友圈管理\n│   │   ├── RobotService.java         # 机器人服务\n│   │   ├── ChannelServiceApi.java    # 频道服务API\n│   │   ├── MeshAdmin.java            # Mesh分布式管理\n│   │   └── Main.java                 # 测试主程序\n│   │   └── messagecontent/           # 消息内容类\n│   │       ├── MessageContent.java\n│   │       ├── TextMessageContent.java\n│   │       ├── ImageMessageContent.java\n│   │       ├── SoundMessageContent.java\n│   │       ├── VideoMessageContent.java\n│   │       ├── FileMessageContent.java\n│   │       └── ...\n│   ├── common/                       # 公共模块（依赖）\n│   └── proto/                        # 协议常量\n└── pom.xml                           # Maven配置\n```\n\n## 主要 API 说明\n\n### 用户管理 (UserAdmin)\n\n| 方法 | 说明 |\n|------|------|\n| `createUser()` | 创建用户 |\n| `getUserByName()` | 按用户名获取用户 |\n| `getUserByMobile()` | 按手机号获取用户 |\n| `getUserByUserId()` | 按用户ID获取用户 |\n| `updateUserInfo()` | 更新用户信息 |\n| `getUserToken()` | 获取用户IM Token |\n| `updateUserBlockStatus()` | 封禁/解封用户 |\n| `checkUserOnlineStatus()` | 检查用户在线状态 |\n\n### 群组管理 (GroupAdmin)\n\n| 方法 | 说明 |\n|------|------|\n| `createGroup()` | 创建群组 |\n| `getGroupInfo()` | 获取群组信息 |\n| `addGroupMembers()` | 添加群成员 |\n| `kickoffGroupMembers()` | 踢出群成员 |\n| `transferGroup()` | 转让群主 |\n| `dismissGroup()` | 解散群组 |\n\n### 消息管理 (MessageAdmin)\n\n| 方法 | 说明 |\n|------|------|\n| `sendMessage()` | 发送消息 |\n| `broadcastMessage()` | 广播消息 |\n| `multicastMessage()` | 群发消息 |\n| `recallMessage()` | 撤回消息 |\n| `deleteMessage()` | 删除消息 |\n\n### 好友关系 (RelationAdmin)\n\n| 方法 | 说明 |\n|------|------|\n| `setUserFriend()` | 设置好友关系 |\n| `getFriendList()` | 获取好友列表 |\n| `setUserBlacklist()` | 设置黑名单 |\n| `getUserBlacklist()` | 获取黑名单列表 |\n\n## 接口文档\n\n- [Admin API 文档](https://docs.wildfirechat.cn/server/admin_api/) - 服务端管理接口，包括用户、群组、消息、频道等管理功能\n- [Robot API 文档](https://docs.wildfirechat.cn/server/robot_api/) - 机器人服务接口，用于开发机器人应用\n- [Channel API 文档](https://docs.wildfirechat.cn/server/channel_api/) - 频道服务接口，用于开发公众号/频道应用\n- [IM 开发文档](https://docs.wildfirechat.cn/) - 野火IM完整开发文档\n\n## 其他语言 SDK\n\n| 语言 | GitHub                                                           | Gitee(码云) |\n|------|------------------------------------------------------------------|-------------|\n| Java SDK | [GitHub](https://github.com/wildfirechat/server/tree/master/sdk) | [Gitee](https://gitee.com/wfchat/im-server/tree/wildfirechat/sdk) |\n| Python SDK | [GitHub](https://github.com/wildfirechat/server-sdk-python)  | [Gitee](https://gitee.com/wfchat/im-server/server-sdk-python) |\n| Go SDK | [GitHub](https://github.com/wildfirechat/server-sdk-go)          | [Gitee](https://gitee.com/wfchat/server-sdk-go) |\n| Node.js SDK | [GitHub](https://github.com/wildfirechat/server-sdk.js)          | [Gitee](https://gitee.com/wfchat/server-sdk.js) |\n\n## 相关链接\n\n- [野火IM 官网](https://wildfirechat.cn/)\n- [在线文档](https://docs.wildfirechat.cn/)\n- [服务端源码 - GitHub](https://github.com/wildfirechat/server) | [Gitee](https://gitee.com/wfchat/im-server)\n- [应用服务源码 - GitHub](https://github.com/wildfirechat/app-server) | [Gitee](https://gitee.com/wfchat/app-server)\n- [机器人服务源码 - GitHub](https://github.com/wildfirechat/robot-server) | [Gitee](https://gitee.com/wfchat/robot-server)\n- [推送服务源码 - GitHub](https://github.com/wildfirechat/push-server) | [Gitee](https://gitee.com/wfchat/push-server)\n- [论坛交流](https://bbs.wildfirechat.cn/)\n\n## 注意事项\n\n1. **Admin API** 使用 18080 端口，具有超级管理权限，理论上不应对外开放，也不应让非内部服务知悉密钥。\n2. **Robot API** 和 **Channel API** 使用 IM 服务的公开端口（默认 80），第三方可以使用机器人或频道与 IM 系统进行对接。\n3. 商业版服务器支持更多高级功能，如在线用户统计、设备管理等。\n4. 高级音视频功能需要单独启用，支持会议管理相关 API。\n\n## 许可证\n\n本项目采用与野火IM相同的许可证。\n"
  },
  {
    "path": "sdk/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>wildfirechat-parent</artifactId>\n        <groupId>cn.wildfirechat</groupId>\n        <version>1.4.5</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>sdk</artifactId>\n\n    <dependencies>\n        <dependency>\n            <groupId>com.google.code.gson</groupId>\n            <artifactId>gson</artifactId>\n            <version>2.8.9</version>\n        </dependency>\n\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n            <version>2.7</version>\n        </dependency>\n\n        <dependency>\n            <groupId>com.googlecode.json-simple</groupId>\n            <artifactId>json-simple</artifactId>\n            <version>1.1.1</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n            <version>1.7.5</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-log4j12</artifactId>\n            <version>1.7.5</version>\n        </dependency>\n\n\n        <dependency>\n            <groupId>commons-httpclient</groupId>\n            <artifactId>commons-httpclient</artifactId>\n            <version>3.1</version>\n        </dependency>\n\n        <dependency>\n            <groupId>uk.org.lidalia</groupId>\n            <artifactId>slf4j-test</artifactId>\n            <version>1.0.0-jdk6</version>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.mockito</groupId>\n            <artifactId>mockito-all</artifactId>\n            <version>1.9.5</version>\n            <type>jar</type>\n            <scope>test</scope>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpclient</artifactId>\n            <version>4.5.13</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.httpcomponents</groupId>\n            <artifactId>httpmime</artifactId>\n            <version>4.5.13</version>\n        </dependency>\n\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n            <version>1.13</version>\n        </dependency>\n\n        <dependency>\n            <groupId>cn.wildfirechat</groupId>\n            <artifactId>common</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n    </dependencies>\n\n    <build>\n        <finalName>${project.artifactId}-${version}</finalName>\n        <defaultGoal>install</defaultGoal>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-assembly-plugin</artifactId>\n                <configuration>\n                    <descriptorRefs>\n                        <descriptorRef>jar-with-dependencies</descriptorRef>\n                    </descriptorRefs>\n                    <finalName>checker</finalName>\n                    <appendAssemblyId>false</appendAssemblyId>\n                    <archive>\n                        <manifest>\n                            <mainClass>cn.wildfirechat.sdk.Main</mainClass>\n                        </manifest>\n                    </archive>\n                </configuration>\n                <executions>\n                    <execution>\n                        <id>assemble-all</id>\n                        <phase>package</phase>\n                        <goals>\n                            <goal>single</goal>\n                        </goals>\n                    </execution>\n                </executions>\n            </plugin>\n\n        </plugins>\n    </build>\n</project>\n"
  },
  {
    "path": "sdk/sdk_readme.txt",
    "content": "    SDK使用说明：\n        1. 把common.jar和sdk.jar 放到lib目录下（如没有需要手动建)。\n        2. 添加下属依赖，注意本地jar包的路径。\n        3. 修改build plugin，把common和sdk打包进去。\n        4. 使用方法请查看sdk.jar/cn.wildfirechat.sdk/Main.class(没有混淆，可以看到源码)\n\n    <!--# 需要添加如下依赖-->\n    <dependencies>\n\t\t<dependency>\n\t\t\t<groupId>com.google.code.gson</groupId>\n\t\t\t<artifactId>gson</artifactId>\n\t\t\t<version>2.8.9</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>commons-httpclient</groupId>\n\t\t\t<artifactId>commons-httpclient</artifactId>\n\t\t\t<version>3.1</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>org.apache.httpcomponents</groupId>\n\t\t\t<artifactId>httpclient</artifactId>\n\t\t\t<version>4.5.13</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>commons-codec</groupId>\n\t\t\t<artifactId>commons-codec</artifactId>\n\t\t\t<version>1.15</version>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>com.google.protobuf</groupId>\n\t\t\t<artifactId>protobuf-java</artifactId>\n\t\t\t<version>2.5.0</version>\n\t\t</dependency>\n\n\t\t<dependency>\n            <groupId>com.googlecode.json-simple</groupId>\n            <artifactId>json-simple</artifactId>\n            <version>1.1.1</version>\n        </dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>cn.wildfirechat</groupId>\n\t\t\t<artifactId>sdk</artifactId>\n\t\t\t<version>1.2.2</version>\n\t\t\t<scope>system</scope>\n\t\t\t<systemPath>${project.basedir}/src/lib/sdk-1.1.9.jar</systemPath>\n\t\t</dependency>\n\n\t\t<dependency>\n\t\t\t<groupId>cn.wildfirechat</groupId>\n\t\t\t<artifactId>common</artifactId>\n\t\t\t<version>1.2.2</version>\n\t\t\t<scope>system</scope>\n\t\t\t<systemPath>${project.basedir}/src/lib/common-1.1.9.jar</systemPath>\n\t\t</dependency>\n\t</dependencies>\n\n    <!--# 由于添加了本地jar包，需要打包时把sdk和common打进去，下面是springboot项目添加includeSystemScope部分，其它类型项目请百度。 -->\n\t<build>\n    \t<plugins>\n    \t\t<plugin>\n    \t\t\t<groupId>org.springframework.boot</groupId>\n    \t\t\t<artifactId>spring-boot-maven-plugin</artifactId>\n    \t\t\t<configuration>\n    \t\t\t\t<includeSystemScope>true</includeSystemScope>\n    \t\t\t</configuration>\n    \t\t</plugin>\n    \t</plugins>\n    </build>\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/AdminConfig.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\n\n/**\n * 管理员配置类\n * <p>\n * 用于初始化管理员SDK的配置，包括IM服务器URL和密钥。\n * 在使用任何Admin功能之前，必须先调用initAdmin方法进行初始化。\n * </p>\n */\npublic class AdminConfig {\n    /**\n     * 初始化管理员配置\n     * <p>\n     * 在使用任何Admin功能之前，必须先调用此方法进行初始化。\n     * </p>\n     * @param url IM服务器地址，例如: http://your-im-server.com\n     * @param secret 管理员密钥，在服务器配置中设置\n     */\n    public static void initAdmin(String url, String secret) {\n        AdminHttpUtils.init(url, secret);\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/ChannelAdmin.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\n\n/**\n * 频道管理类\n * <p>\n * 提供频道管理相关的功能，包括：\n * <ul>\n * <li>创建和销毁频道</li>\n * <li>获取频道信息</li>\n * <li>用户订阅/取消订阅频道</li>\n * <li>检查用户是否订阅频道</li>\n * </ul>\n * </p>\n */\npublic class ChannelAdmin {\n    /**\n     * 创建频道\n     * @param inputCreateChannel 频道创建信息\n     * @return 创建结果，包含频道ID\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputCreateChannel> createChannel(InputCreateChannel inputCreateChannel) throws Exception {\n        String path = APIPath.Create_Channel;\n        return AdminHttpUtils.httpJsonPost(path, inputCreateChannel, OutputCreateChannel.class);\n    }\n\n    /**\n     * 销毁频道\n     * @param channelId 频道ID\n     * @return 销毁结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> destroyChannel(String channelId) throws Exception {\n        String path = APIPath.Destroy_Channel;\n        InputChannelId inputChannelId = new InputChannelId(channelId);\n        return AdminHttpUtils.httpJsonPost(path, inputChannelId, Void.class);\n    }\n\n    /**\n     * 获取频道信息\n     * @param channelId 频道ID\n     * @return 频道信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputGetChannelInfo> getChannelInfo(String channelId) throws Exception {\n        String path = APIPath.Get_Channel_Info;\n        InputChannelId inputChannelId = new InputChannelId(channelId);\n        return AdminHttpUtils.httpJsonPost(path, inputChannelId, OutputGetChannelInfo.class);\n    }\n\n    /**\n     * 订阅频道\n     * @param channelId 频道ID\n     * @param userId 用户ID\n     * @return 订阅结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> subscribeChannel(String channelId, String userId) throws Exception {\n        String path = APIPath.Subscribe_Channel;\n        InputSubscribeChannel input = new InputSubscribeChannel(channelId, userId, 1);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 取消订阅频道\n     * @param channelId 频道ID\n     * @param userId 用户ID\n     * @return 取消订阅结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> unsubscribeChannel(String channelId, String userId) throws Exception {\n        String path = APIPath.Subscribe_Channel;\n        InputSubscribeChannel input = new InputSubscribeChannel(channelId, userId, 0);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 检查用户是否订阅了频道\n     * @param userId 用户ID\n     * @param channelId 频道ID\n     * @return true-已订阅，false-未订阅\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputBooleanValue> isUserSubscribedChannel(String userId, String channelId) throws Exception {\n        String path = APIPath.Check_User_Subscribe_Channel;\n        InputSubscribeChannel input = new InputSubscribeChannel(channelId, userId, 0);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputBooleanValue.class);\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/ChannelServiceApi.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\nimport cn.wildfirechat.sdk.utilities.ChannelHttpUtils;\nimport com.google.gson.Gson;\nimport org.apache.commons.codec.digest.DigestUtils;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.util.List;\n\nimport static cn.wildfirechat.proto.ProtoConstants.ApplicationType.ApplicationType_Channel;\n\n/**\n * 频道服务类（仅专业版支持，社区版不支持）\n * <p>\n * 提供频道相关的功能，包括：\n * <ul>\n * <li>获取用户信息</li>\n * <li>修改频道信息</li>\n * <li>发送和撤回消息</li>\n * <li>用户订阅管理</li>\n * <li>订阅者列表查询</li>\n * </ul>\n * </p>\n */\npublic class ChannelServiceApi implements Closeable {\n    private final ChannelHttpUtils channelHttpUtils;\n\n    /**\n     * 创建频道服务实例\n     * @param imurl IM服务器地址\n     * @param channelId 频道ID\n     * @param secret 频道密钥\n     */\n    public ChannelServiceApi(String imurl, String channelId, String secret) {\n        channelHttpUtils = new ChannelHttpUtils(imurl, channelId, secret);\n    }\n\n    public IMResult<InputOutputUserInfo> getUserInfo(String userId) throws Exception {\n        String path = APIPath.Channel_User_Info;\n        InputGetUserInfo getUserInfo = new InputGetUserInfo(userId, null, null);\n        return channelHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);\n    }\n\n    public IMResult<InputOutputUserInfo> getUserInfoByName(String userName) throws Exception {\n        String path = APIPath.Channel_User_Info;\n        InputGetUserInfo getUserInfo = new InputGetUserInfo(null, userName, null);\n        return channelHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);\n    }\n\n    public IMResult<InputOutputUserInfo> getUserInfoByMobile(String mobile) throws Exception {\n        String path = APIPath.Channel_User_Info;\n        InputGetUserInfo getUserInfo = new InputGetUserInfo(null, null, mobile);\n        return channelHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);\n    }\n\n    public IMResult<Void> modifyChannelInfo(/*ProtoConstants.ModifyChannelInfoType*/int type, String value) throws Exception {\n        String path = APIPath.Channel_Update_Profile;\n        InputModifyChannelInfo modifyChannelInfo = new InputModifyChannelInfo();\n        modifyChannelInfo.setType(type);\n        modifyChannelInfo.setValue(value);\n        return channelHttpUtils.httpJsonPost(path, modifyChannelInfo, Void.class);\n    }\n\n    public IMResult<OutputGetChannelInfo> getChannelInfo() throws Exception {\n        String path = APIPath.Channel_Get_Profile;\n        return channelHttpUtils.httpJsonPost(path, null, OutputGetChannelInfo.class);\n    }\n\n    public IMResult<Void> modifyChannelMenu(List<PojoChannelMenu> menus) throws Exception {\n        String menuStr = new Gson().toJson(menus);\n        return modifyChannelInfo(ProtoConstants.ModifyChannelInfoType.Modify_Channel_Menu, menuStr);\n    }\n\n    public IMResult<SendMessageResult> sendMessage(int line, List<String> targets, MessagePayload payload) throws Exception {\n        String path = APIPath.Channel_Message_Send;\n        SendChannelMessageData messageData = new SendChannelMessageData();\n        messageData.setLine(line);\n        messageData.setTargets(targets);\n        messageData.setPayload(payload);\n        return channelHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class);\n    }\n\n    public IMResult<String> recallMessage(long messageUid) throws Exception {\n        String path = APIPath.Channel_Msg_Recall;\n        RecallMessageData messageData = new RecallMessageData();\n        messageData.setMessageUid(messageUid);\n        return channelHttpUtils.httpJsonPost(path, messageData, String.class);\n    }\n\n    public IMResult<Void> republishMessage(long messageUid, List<String> targets) throws Exception {\n        String path = APIPath.Channel_Msg_Republish;\n        RepublishChannelMessageData messageData = new RepublishChannelMessageData();\n        messageData.setMessageId(messageUid);\n        messageData.setTargets(targets);\n        return channelHttpUtils.httpJsonPost(path, messageData, Void.class);\n    }\n\n    public IMResult<Void> subscribe(String userId) throws Exception {\n        String path = APIPath.Channel_Subscribe;\n        InputChannelSubscribe input = new InputChannelSubscribe();\n        input.setTarget(userId);\n        input.setSubscribe(1);\n        return channelHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    public IMResult<Void> unsubscribe(String userId) throws Exception {\n        String path = APIPath.Channel_Subscribe;\n        InputChannelSubscribe input = new InputChannelSubscribe();\n        input.setTarget(userId);\n        input.setSubscribe(0);\n        return channelHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    public IMResult<OutputStringList> getSubscriberList() throws Exception {\n        String path = APIPath.Channel_Subscriber_List;\n        return channelHttpUtils.httpJsonPost(path, null, OutputStringList.class);\n    }\n\n    public IMResult<Boolean> isSubscriber(String userId) throws Exception {\n        String path = APIPath.Channel_Is_Subscriber;\n        InputUserId input = new InputUserId(userId);\n        return channelHttpUtils.httpJsonPost(path, input, Boolean.class);\n    }\n\n    public IMResult<OutputApplicationUserInfo> applicationGetUserInfo(String authCode) throws Exception {\n        String path = APIPath.Channel_Application_Get_UserInfo;\n        InputApplicationGetUserInfo input = new InputApplicationGetUserInfo();\n        input.setAuthCode(authCode);\n        return channelHttpUtils.httpJsonPost(path, input, OutputApplicationUserInfo.class);\n    }\n\n    public OutputApplicationConfigData getApplicationSignature() {\n        int nonce = (int)(Math.random() * 100000 + 3);\n        long timestamp = System.currentTimeMillis()/1000;\n        String str = nonce + \"|\" + channelHttpUtils.getChannelId() + \"|\" + timestamp + \"|\" + channelHttpUtils.getChannelSecret();\n        String sign = DigestUtils.sha1Hex(str);\n        OutputApplicationConfigData configData = new OutputApplicationConfigData();\n        configData.setAppId(channelHttpUtils.getChannelId());\n        configData.setAppType(ApplicationType_Channel);\n        configData.setTimestamp(timestamp);\n        configData.setNonceStr(nonce+\"\");\n        configData.setSignature(sign);\n        return configData;\n    }\n\n    @Override\n    public void close() throws IOException {\n        channelHttpUtils.close();\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/ChatroomAdmin.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\n\n/**\n * 聊天室管理类\n * <p>\n * 提供聊天室管理相关的功能，包括：\n * <ul>\n * <li>创建和销毁聊天室</li>\n * <li>获取聊天室信息</li>\n * <li>聊天室成员管理</li>\n * <li>聊天室黑名单管理（仅专业版）</li>\n * <li>聊天室管理员设置</li>\n * <li>聊天室全员禁言</li>\n * </ul>\n * </p>\n */\npublic class ChatroomAdmin {\n    /**\n     * 创建聊天室\n     * @param chatroomId 聊天室ID（为空时自动生成）\n     * @param title 聊天室标题\n     * @param desc 聊天室描述\n     * @param portrait 聊天室头像\n     * @param extra 额外信息\n     * @param state 聊天室状态\n     * @return 创建结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputCreateChatroom> createChatroom(String chatroomId, String title, String desc ,String portrait, String extra, Integer state) throws Exception {\n        String path = APIPath.Create_Chatroom;\n        InputCreateChatroom input = new InputCreateChatroom();\n        input.setChatroomId(chatroomId);\n        input.setTitle(title);\n        input.setDesc(desc);\n        input.setPortrait(portrait);\n        input.setExtra(extra);\n        input.setState(state);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputCreateChatroom.class);\n    }\n\n    /**\n     * 销毁聊天室\n     * @param chatroomId 聊天室ID\n     * @return 销毁结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> destroyChatroom(String chatroomId) throws Exception {\n        String path = APIPath.Chatroom_Destroy;\n        InputDestoryChatroom input = new InputDestoryChatroom();\n        input.setChatroomId(chatroomId);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 获取聊天室信息\n     * @param chatroomId 聊天室ID\n     * @return 聊天室信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputGetChatroomInfo> getChatroomInfo(String chatroomId) throws Exception {\n        String path = APIPath.Chatroom_Info;\n        InputGetChatroomInfo input = new InputGetChatroomInfo(chatroomId);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputGetChatroomInfo.class);\n    }\n\n    /**\n     * 获取聊天室成员列表\n     * @param chatroomId 聊天室ID\n     * @return 成员ID列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputStringList> getChatroomMembers(String chatroomId) throws Exception {\n        String path = APIPath.Chatroom_GetMembers;\n        InputGetChatroomInfo input = new InputGetChatroomInfo(chatroomId);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputStringList.class);\n    }\n\n    /**\n     * 获取用户所在的聊天室\n     * @param userId 用户ID\n     * @return 用户所在的聊天室信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputUserChatroom> getUserChatroom(String userId) throws Exception {\n        String path = APIPath.Chatroom_GetUserChatroom;\n        InputUserId input = new InputUserId(userId);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputUserChatroom.class);\n    }\n\n    /**\n     * 设置聊天室黑名单状态（仅专业版支持）\n     * <p>status：0-正常；1-禁言；2-禁止加入</p>\n     * @param chatroomId 聊天室ID\n     * @param userId 用户ID\n     * @param status 状态值\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setChatroomBlacklist(String chatroomId, String userId, int status) throws Exception {\n        String path = APIPath.Chatroom_SetBlacklist;\n        InputSetChatroomBlacklist input = new InputSetChatroomBlacklist(chatroomId, userId, status, 0);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 获取聊天室黑名单\n     * @param chatroomId 聊天室ID\n     * @return 黑名单信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputChatroomBlackInfos> getChatroomBlacklist(String chatroomId) throws Exception {\n        String path = APIPath.Chatroom_GetBlacklist;\n        InputChatroomId input = new InputChatroomId(chatroomId);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputChatroomBlackInfos.class);\n    }\n\n    /**\n     * 设置聊天室管理员\n     * <p>status：1-设置为管理员；0-取消管理员</p>\n     * @param chatroomId 聊天室ID\n     * @param userId 用户ID\n     * @param status 状态值\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setChatroomManager(String chatroomId, String userId, int status) throws Exception {\n        String path = APIPath.Chatroom_SetManager;\n        InputSetChatroomManager input = new InputSetChatroomManager(chatroomId, userId, status);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 获取聊天室管理员列表\n     * @param chatroomId 聊天室ID\n     * @return 管理员ID列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputStringList> getChatroomManagerList(String chatroomId) throws Exception {\n        String path = APIPath.Chatroom_GetManagerList;\n        InputChatroomId input = new InputChatroomId(chatroomId);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputStringList.class);\n    }\n\n    /**\n     * 设置聊天室全员禁言\n     * @param chatroomId 聊天室ID\n     * @param mute true-全员禁言，false-取消全员禁言\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setChatroomMute(String chatroomId, boolean mute) throws Exception {\n        String path = APIPath.Chatroom_MuteAll;\n        InputChatroomMute input = new InputChatroomMute(chatroomId, mute ? 1 : 0);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/ConferenceAdmin.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\n\n/**\n * 会议管理类\n * <p>\n * 提供音视频会议管理相关的功能，包括：\n * <ul>\n * <li>会议列表查询</li>\n * <li>会议创建和销毁</li>\n * <li>会议参与者管理</li>\n * <li>会议录制控制</li>\n * <li>RTP转发管理</li>\n * </ul>\n * </p>\n */\npublic class ConferenceAdmin {\n    /**\n     * 获取会议列表（分页）\n     * @param count 每页数量\n     * @param offset 偏移量\n     * @return 会议信息列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<PojoConferenceInfoList> listConferences(int count, int offset) throws Exception {\n        String path = APIPath.Conference_List;\n        InputCountOffset inputCountOffset = new InputCountOffset();\n        inputCountOffset.count = count;\n        inputCountOffset.offset = offset;\n        return AdminHttpUtils.httpJsonPost(path, inputCountOffset, PojoConferenceInfoList.class);\n    }\n\n    /**\n     * 检查会议是否存在\n     * @param conferenceId 会议ID\n     * @return true-存在，false-不存在\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Boolean> existsConferences(String conferenceId) throws Exception {\n        String path = APIPath.Conference_Exist;\n        PojoConferenceRoomId data = new PojoConferenceRoomId(conferenceId, false);\n        return AdminHttpUtils.httpJsonPost(path, data, Boolean.class);\n    }\n\n    /**\n     * 获取会议参与者列表\n     * @param roomId 房间ID\n     * @param advance 是否使用高级模式\n     * @return 参与者列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<PojoConferenceParticipantList> listParticipants(String roomId, boolean advance) throws Exception {\n        String path = APIPath.Conference_List_Participant;\n        PojoConferenceRoomId data = new PojoConferenceRoomId(roomId, advance);\n        return AdminHttpUtils.httpJsonPost(path, data, PojoConferenceParticipantList.class);\n    }\n\n    /**\n     * 创建会议房间\n     * @param roomId 房间ID\n     * @param description 描述\n     * @param pin 房间密码\n     * @param maxPublisher 最大推流数\n     * @param advance 是否使用高级模式\n     * @param bitrate 比特率\n     * @param recording 是否录制\n     * @param permanent 是否永久房间\n     * @return 创建结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> createRoom(String roomId, String description, String pin, int maxPublisher, boolean advance, int bitrate, boolean recording, boolean permanent) throws Exception {\n        String path = APIPath.Conference_Create;\n        PojoConferenceCreate create = new PojoConferenceCreate();\n        create.roomId = roomId;\n        create.description = description;\n        create.pin = pin;\n        create.max_publishers = maxPublisher;\n        create.advance = advance;\n        create.bitrate = bitrate;\n        create.recording = recording;\n        create.permanent = permanent;\n        return AdminHttpUtils.httpJsonPost(path, create, Void.class);\n    }\n\n    /**\n     * 启用或禁用会议录制\n     * @param roomId 房间ID\n     * @param advance 是否使用高级模式\n     * @param recording true-启用录制，false-禁用录制\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> enableRecording(String roomId, boolean advance, boolean recording) throws Exception {\n        String path = APIPath.Conference_Recording;\n        PojoConferenceRecording create = new PojoConferenceRecording();\n        create.roomId = roomId;\n        create.recording = recording;\n        create.advance = advance;\n        return AdminHttpUtils.httpJsonPost(path, create, Void.class);\n    }\n\n    /**\n     * 销毁会议房间\n     * @param roomId 房间ID\n     * @param advance 是否使用高级模式\n     * @return 销毁结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> destroy(String roomId, boolean advance) throws Exception {\n        String path = APIPath.Conference_Destroy;\n        PojoConferenceRoomId conferenceRoomId = new PojoConferenceRoomId(roomId, advance);\n        return AdminHttpUtils.httpJsonPost(path, conferenceRoomId, Void.class);\n    }\n\n    /**\n     * RTP转发\n     * @param roomId 房间ID\n     * @param userId 用户ID\n     * @param rtpHost RTP主机地址\n     * @param audioPort 音频端口\n     * @param audioPt 音频Payload类型\n     * @param audioSSRC 音频SSRC\n     * @param videoPort 视频端口\n     * @param videoPt 视频Payload类型\n     * @param videoSSRC 视频SSRC\n     * @return 转发结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> rtpForward(String roomId, String userId, String rtpHost, int audioPort, int audioPt, long audioSSRC, int videoPort, int videoPt, long videoSSRC) throws Exception {\n        String path = APIPath.Conference_Rtp_Forward;\n        PojoConferenceRtpForwardReq req = new PojoConferenceRtpForwardReq(roomId, userId, rtpHost, audioPort, audioPt, audioSSRC, videoPort, videoPt, videoSSRC);\n        return AdminHttpUtils.httpJsonPost(path, req, Void.class);\n    }\n\n    /**\n     * 停止RTP转发\n     * @param roomId 房间ID\n     * @param userId 用户ID\n     * @param streamId 流ID\n     * @return 停止结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> stopRtpForward(String roomId, String userId, long streamId) throws Exception {\n        String path = APIPath.Conference_Stop_Rtp_Forward;\n        PojoConferenceStopRtpForwardReq req = new PojoConferenceStopRtpForwardReq(roomId, userId, streamId);\n        return AdminHttpUtils.httpJsonPost(path, req, Void.class);\n    }\n\n    /**\n     * 获取RTP转发列表\n     * @param roomId 房间ID\n     * @return RTP转发列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<PojoConferenceRtpForwarders> listRtpForwarders(String roomId) throws Exception {\n        String path = APIPath.Conference_List_Rtp_Forward;\n        PojoConferenceRoomId req = new PojoConferenceRoomId();\n        req.roomId = roomId;\n        return AdminHttpUtils.httpJsonPost(path, req, PojoConferenceRtpForwarders.class);\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/GeneralAdmin.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.HttpStatus;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.client.methods.HttpPut;\nimport org.apache.http.entity.ContentType;\nimport org.apache.http.entity.FileEntity;\nimport org.apache.http.entity.InputStreamEntity;\nimport org.apache.http.entity.mime.MultipartEntityBuilder;\nimport org.apache.http.entity.mime.content.FileBody;\nimport org.apache.http.entity.mime.content.InputStreamBody;\nimport org.apache.http.util.EntityUtils;\n\nimport java.io.File;\nimport java.io.InputStream;\nimport java.net.URLConnection;\n\n/**\n * 通用管理类\n * <p>\n * 提供通用的系统管理功能，包括：\n * <ul>\n * <li>系统设置管理</li>\n * <li>文件管理（会话文件、用户文件）</li>\n * <li>用户设置管理（会话置顶等）</li>\n * <li>健康检查</li>\n * <li>频道管理（已废弃，请使用ChannelAdmin）</li>\n * </ul>\n * </p>\n */\npublic class GeneralAdmin {\n    /**\n     * 获取系统设置\n     * @param id 设置项ID\n     * @return 系统设置信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<SystemSettingPojo> getSystemSetting(int id) throws Exception {\n        String path = APIPath.Get_System_Setting;\n        SystemSettingPojo input = new SystemSettingPojo();\n        input.id = id;\n        return AdminHttpUtils.httpJsonPost(path, input, SystemSettingPojo.class);\n    }\n\n    /**\n     * 设置系统设置\n     * @param id 设置项ID\n     * @param value 设置值\n     * @param desc 设置描述\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setSystemSetting(int id, String value, String desc) throws Exception {\n        String path = APIPath.Put_System_Setting;\n        SystemSettingPojo input = new SystemSettingPojo();\n        input.id = id;\n        input.value = value;\n        input.desc = desc;\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * @deprecated 请使用 {@link cn.wildfirechat.sdk.ChannelAdmin#createChannel(InputCreateChannel inputCreateChannel)} 代替此方法，因为它将在未来的版本中被移除。\n     */\n    @Deprecated\n    public static IMResult<OutputCreateChannel> createChannel(InputCreateChannel inputCreateChannel) throws Exception {\n        String path = APIPath.Create_Channel;\n        return AdminHttpUtils.httpJsonPost(path, inputCreateChannel, OutputCreateChannel.class);\n    }\n\n    /**\n     * @deprecated 请使用 {@link cn.wildfirechat.sdk.ChannelAdmin#destroyChannel(String channelId)} 代替此方法，因为它将在未来的版本中被移除。\n     */\n    @Deprecated\n    public static IMResult<Void> destroyChannel(String channelId) throws Exception {\n        String path = APIPath.Destroy_Channel;\n        InputChannelId inputChannelId = new InputChannelId(channelId);\n        return AdminHttpUtils.httpJsonPost(path, inputChannelId, Void.class);\n    }\n\n    /**\n     * @deprecated 请使用 {@link cn.wildfirechat.sdk.ChannelAdmin#getChannelInfo(String channelId)} 代替此方法，因为它将在未来的版本中被移除。\n     */\n    @Deprecated\n    public static IMResult<OutputGetChannelInfo> getChannelInfo(String channelId) throws Exception {\n        String path = APIPath.Get_Channel_Info;\n        InputChannelId inputChannelId = new InputChannelId(channelId);\n        return AdminHttpUtils.httpJsonPost(path, inputChannelId, OutputGetChannelInfo.class);\n    }\n\n    /**\n     * @deprecated 请使用 {@link cn.wildfirechat.sdk.ChannelAdmin#subscribeChannel(String userId, String channelId)} 代替此方法，因为它将在未来的版本中被移除。\n     */\n    @Deprecated\n    public static IMResult<Void> subscribeChannel(String channelId, String userId) throws Exception {\n        String path = APIPath.Subscribe_Channel;\n        InputSubscribeChannel input = new InputSubscribeChannel(channelId, userId, 1);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * @deprecated 请使用 {@link cn.wildfirechat.sdk.ChannelAdmin#unsubscribeChannel(String userId, String channelId)} 代替此方法，因为它将在未来的版本中被移除。\n     */\n    @Deprecated\n    public static IMResult<Void> unsubscribeChannel(String channelId, String userId) throws Exception {\n        String path = APIPath.Subscribe_Channel;\n        InputSubscribeChannel input = new InputSubscribeChannel(channelId, userId, 0);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * @deprecated 请使用 {@link cn.wildfirechat.sdk.ChannelAdmin#isUserSubscribedChannel(String userId, String channelId)} 代替此方法，因为它将在未来的版本中被移除。\n     */\n    @Deprecated\n    public static IMResult<OutputBooleanValue> isUserSubscribedChannel(String userId, String channelId) throws Exception {\n        String path = APIPath.Check_User_Subscribe_Channel;\n        InputSubscribeChannel input = new InputSubscribeChannel(channelId, userId, 0);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputBooleanValue.class);\n    }\n\n    /**\n     * 获取会话文件列表（仅专业版支持）\n     * <p>\n     * 如果是单聊会话，target和userId代表会话的2个用户；如果是其他会话userId无意义。\n     * </p>\n     * @param conversationType 会话类型\n     * @param target 会话目标ID\n     * @param line 线路\n     * @param userId 用户ID\n     * @param offset 偏移量\n     * @param desc 是否降序\n     * @param count 每页数量\n     * @return 文件列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<FilesPojo> getConversationFiles(int conversationType, String target, int line, String userId, int offset, boolean desc, int count) throws Exception {\n        String path = APIPath.Get_Conversation_Files;\n        GetConversationFilesPojo input = new GetConversationFilesPojo();\n        input.conversationType = conversationType;\n        input.target = target;\n        input.line = line;\n        input.userId = userId;\n        input.offset = offset;\n        input.desc = desc;\n        input.count = count;\n        return AdminHttpUtils.httpJsonPost(path, input, FilesPojo.class);\n    }\n\n    /**\n     * 获取用户文件列表\n     * @param userId 用户ID\n     * @param offset 偏移量\n     * @param desc 是否降序\n     * @param count 每页数量\n     * @return 文件列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<FilesPojo> getUserFiles(String userId, int offset, boolean desc, int count) throws Exception {\n        String path = APIPath.Get_User_Files;\n        GetUserFilesPojo input = new GetUserFilesPojo();\n        input.userId = userId;\n        input.offset = offset;\n        input.desc = desc;\n        input.count = count;\n        return AdminHttpUtils.httpJsonPost(path, input, FilesPojo.class);\n    }\n\n    /**\n     * 根据消息ID获取文件信息\n     * @param messageId 消息ID\n     * @return 文件信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<FilesPojo.FilePojo> getFile(long messageId) throws Exception {\n        String path = APIPath.Get_Message_File;\n        LongPojo input = new LongPojo();\n        input.value = messageId;\n        return AdminHttpUtils.httpJsonPost(path, input, FilesPojo.FilePojo.class);\n    }\n\n    /**\n     * 设置会话置顶\n     * @param userId 用户ID\n     * @param conversationType 会话类型\n     * @param target 会话目标ID\n     * @param line 线路\n     * @param isTop true-置顶，false-取消置顶\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setConversationTop(String userId, int conversationType, String target, int line, boolean isTop) throws Exception {\n        String key = conversationType + \"-\" + line + \"-\" + target;\n        String value = isTop?\"1\":\"0\";\n        return setUserSetting(userId, 3, key, value);\n    }\n\n    /**\n     * 获取会话置顶状态\n     * @param userId 用户ID\n     * @param conversationType 会话类型\n     * @param target 会话目标ID\n     * @param line 线路\n     * @return true-已置顶，false-未置顶\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Boolean> getConversationTop(String userId, int conversationType, String target, int line) throws Exception {\n        String key = conversationType + \"-\" + line + \"-\" + target;\n        IMResult<UserSettingPojo> result = getUserSetting(userId, 3, key);\n        IMResult<Boolean> out = new IMResult<Boolean>();\n        out.code = result.code;\n        out.msg = result.msg;\n        out.result = result.result != null && \"1\".equals(result.result.getValue());\n        return out;\n    }\n\n    /**\n     * 获取用户设置\n     * @param userId 用户ID\n     * @param scope 设置范围\n     * @param key 设置键\n     * @return 用户设置信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<UserSettingPojo> getUserSetting(String userId, int scope, String key) throws Exception {\n        String path = APIPath.User_Get_Setting;\n        UserSettingPojo pojo = new UserSettingPojo();\n        pojo.setUserId(userId);\n        pojo.setScope(scope);\n        pojo.setKey(key);\n        return AdminHttpUtils.httpJsonPost(path, pojo, UserSettingPojo.class);\n    }\n\n    /**\n     * 设置用户设置\n     * @param userId 用户ID\n     * @param scope 设置范围\n     * @param key 设置键\n     * @param value 设置值\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setUserSetting(String userId, int scope, String key, String value) throws Exception {\n        String path = APIPath.User_Put_Setting;\n        UserSettingPojo pojo = new UserSettingPojo();\n        pojo.setUserId(userId);\n        pojo.setScope(scope);\n        pojo.setKey(key);\n        pojo.setValue(value);\n        return AdminHttpUtils.httpJsonPost(path, pojo, Void.class);\n    }\n\n    /**\n     * 健康检查\n     * @return 健康检查结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<HealthCheckResult> healthCheck() throws Exception {\n        return AdminHttpUtils.httpGet(APIPath.Health, HealthCheckResult.class);\n    }\n\n    /**\n     * 获取客户信息\n     * @return 客户信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<String> getCustomer() throws Exception {\n        return AdminHttpUtils.httpJsonPost(APIPath.GET_CUSTOMER, null, String.class);\n    }\n\n    public static IMResult<OutputPresignedUploadUrl> getPresignedUploadUrl(String fileName, int/*ProtoConstants.MessageMediaType*/ mediaType, String contentType) throws Exception {\n        String path = APIPath.Get_Presigned_Upload_Url;\n\n        InputGetPresignedUploadUrl requestPojo = new InputGetPresignedUploadUrl();\n        requestPojo.fileName = fileName;\n        requestPojo.mediaType = mediaType;\n        requestPojo.contentType = contentType;\n        return AdminHttpUtils.httpJsonPost(path, requestPojo, OutputPresignedUploadUrl.class);\n    }\n\n    /**\n     * 根据文件名获取Content-Type\n     *\n     * @param fileName 文件名\n     * @return Content-Type，如果无法识别则返回 \"application/octet-stream\"\n     */\n    private static String getContentTypeByFileName(String fileName) {\n        if (fileName == null || fileName.isEmpty()) {\n            return \"application/octet-stream\";\n        }\n\n        // 首先尝试使用 URLConnection 猜测\n        String contentType = URLConnection.guessContentTypeFromName(fileName);\n\n        // 如果无法识别，使用常见扩展名映射\n        if (contentType == null) {\n            String lowerName = fileName.toLowerCase();\n            if (lowerName.endsWith(\".jpg\") || lowerName.endsWith(\".jpeg\")) {\n                contentType = \"image/jpeg\";\n            } else if (lowerName.endsWith(\".png\")) {\n                contentType = \"image/png\";\n            } else if (lowerName.endsWith(\".gif\")) {\n                contentType = \"image/gif\";\n            } else if (lowerName.endsWith(\".bmp\")) {\n                contentType = \"image/bmp\";\n            } else if (lowerName.endsWith(\".webp\")) {\n                contentType = \"image/webp\";\n            } else if (lowerName.endsWith(\".mp4\")) {\n                contentType = \"video/mp4\";\n            } else if (lowerName.endsWith(\".mov\")) {\n                contentType = \"video/quicktime\";\n            } else if (lowerName.endsWith(\".avi\")) {\n                contentType = \"video/x-msvideo\";\n            } else if (lowerName.endsWith(\".mp3\")) {\n                contentType = \"audio/mpeg\";\n            } else if (lowerName.endsWith(\".wav\")) {\n                contentType = \"audio/wav\";\n            } else if (lowerName.endsWith(\".pdf\")) {\n                contentType = \"application/pdf\";\n            } else if (lowerName.endsWith(\".doc\")) {\n                contentType = \"application/msword\";\n            } else if (lowerName.endsWith(\".docx\")) {\n                contentType = \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\";\n            } else if (lowerName.endsWith(\".xls\")) {\n                contentType = \"application/vnd.ms-excel\";\n            } else if (lowerName.endsWith(\".xlsx\")) {\n                contentType = \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\";\n            } else if (lowerName.endsWith(\".ppt\")) {\n                contentType = \"application/vnd.ms-powerpoint\";\n            } else if (lowerName.endsWith(\".pptx\")) {\n                contentType = \"application/vnd.openxmlformats-officedocument.presentationml.presentation\";\n            } else if (lowerName.endsWith(\".txt\")) {\n                contentType = \"text/plain\";\n            } else if (lowerName.endsWith(\".html\") || lowerName.endsWith(\".htm\")) {\n                contentType = \"text/html\";\n            } else if (lowerName.endsWith(\".json\")) {\n                contentType = \"application/json\";\n            } else if (lowerName.endsWith(\".xml\")) {\n                contentType = \"application/xml\";\n            } else if (lowerName.endsWith(\".zip\")) {\n                contentType = \"application/zip\";\n            } else if (lowerName.endsWith(\".rar\")) {\n                contentType = \"application/x-rar-compressed\";\n            } else if (lowerName.endsWith(\".7z\")) {\n                contentType = \"application/x-7z-compressed\";\n            } else if (lowerName.endsWith(\".tar\")) {\n                contentType = \"application/x-tar\";\n            } else if (lowerName.endsWith(\".gz\")) {\n                contentType = \"application/gzip\";\n            } else {\n                contentType = \"application/octet-stream\";\n            }\n        }\n\n        return contentType;\n    }\n\n\n    /**\n     * 上传文件\n     * <p>\n     * 流程：先调用getPresignedUploadUrl获取预签名上传地址，然后直接上传文件。\n     * 上传成功后返回文件的下载地址等信息。\n     * </p>\n     *\n     * @param file        要上传的文件\n     * @return 上传结果，包含下载地址\n     * @throws Exception 上传失败时抛出异常\n     */\n    public static IMResult<String> uploadFile(File file) throws Exception {\n        return uploadFile(file, ProtoConstants.MessageMediaType.FILE, null);\n    }\n    /**\n     * 上传文件\n     * <p>\n     * 流程：先调用getPresignedUploadUrl获取预签名上传地址，然后直接上传文件。\n     * 上传成功后返回文件的下载地址等信息。\n     * </p>\n     *\n     * @param file        要上传的文件\n     * @param mediaType   媒体类型，参考{@link cn.wildfirechat.proto.ProtoConstants.MessageMediaType}\n     * @param contentType 文件Content-Type，例如 \"image/jpeg\", \"application/octet-stream\" 等；\n     *                    如果为null或空，则根据文件名自动识别\n     * @return 上传结果，包含下载地址\n     * @throws Exception 上传失败时抛出异常\n     */\n    public static IMResult<String> uploadFile(File file, int mediaType, String contentType) throws Exception {\n        if (file == null || !file.exists()) {\n            throw new IllegalArgumentException(\"文件不能为空或不存在\");\n        }\n\n        // 如果未指定Content-Type，根据文件名自动获取\n        if (contentType == null || contentType.isEmpty()) {\n            contentType = getContentTypeByFileName(file.getName());\n        }\n\n        return doUploadFile(file.getName(), mediaType, contentType, file, null);\n    }\n\n    /**\n     * 执行文件上传的公共方法\n     * <p>\n     * 根据服务器类型选择不同的上传方式：\n     * <ul>\n     * <li>type = 1（七牛云）：使用 POST + multipart/form-data 表单上传</li>\n     * <li>type = 其他（阿里云、Minio等）：使用 PUT + 二进制流上传</li>\n     * </ul>\n     * </p>\n     *\n     * @param fileName    文件名\n     * @param mediaType   媒体类型\n     * @param contentType Content-Type\n     * @param file        文件对象（用于七牛云上传）\n     * @param inputStream 输入流（用于其他类型上传，可为null）\n     * @return 上传结果\n     * @throws Exception 上传失败时抛出异常\n     */\n    private static IMResult<String> doUploadFile(String fileName, int mediaType,\n                                          String contentType,\n                                          File file,\n                                          InputStream inputStream) throws Exception {\n        // 1. 获取预签名上传地址\n        IMResult<OutputPresignedUploadUrl> presignedResult = getPresignedUploadUrl(\n            fileName, mediaType, contentType);\n\n        if (presignedResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n            IMResult<String> imResult = new IMResult<>();\n            imResult.setCode(presignedResult.code);\n            imResult.setMsg(presignedResult.msg);\n            return imResult;\n        }\n\n        OutputPresignedUploadUrl presignedUrl = presignedResult.getResult();\n        if (presignedUrl == null || presignedUrl.uploadUrl == null) {\n            throw new Exception(\"预签名上传地址为空\");\n        }\n\n        // 2. 根据服务器类型选择上传方式\n        if (presignedUrl.type == 1) {\n            // 七牛云：使用 POST + multipart/form-data 表单上传\n            return uploadToQiniu(presignedUrl, file, inputStream, fileName, contentType);\n        } else {\n            // 其他（阿里云、Minio、腾讯云、华为云、AWS S3等）：使用 PUT 上传\n            return uploadToOther(presignedUrl, file, inputStream, contentType);\n        }\n    }\n\n    /**\n     * 上传到七牛云（type = 1）\n     * 使用 POST + multipart/form-data 表单格式\n     */\n    private static IMResult<String> uploadToQiniu(OutputPresignedUploadUrl presignedUrl, File file,\n                                           InputStream inputStream, String fileName,\n                                           String contentType) throws Exception {\n        // 解析七牛云上传地址：格式为 \"https://host?token?key\"\n        String uploadUrl = presignedUrl.uploadUrl;\n        String token;\n        String key;\n\n        int tokenStart = uploadUrl.indexOf('?');\n        int keyStart = uploadUrl.indexOf('?', tokenStart + 1);\n\n        if (tokenStart == -1 || keyStart == -1) {\n            throw new Exception(\"七牛云上传地址格式错误\");\n        }\n\n        String baseUrl = uploadUrl.substring(0, tokenStart);\n        token = uploadUrl.substring(tokenStart + 1, keyStart);\n        key = uploadUrl.substring(keyStart + 1);\n\n        HttpPost httpPost = new HttpPost(baseUrl);\n        try {\n            MultipartEntityBuilder builder = MultipartEntityBuilder.create();\n\n            // 添加 token 和 key 字段\n            builder.addTextBody(\"token\", token);\n            builder.addTextBody(\"key\", key);\n\n            // 添加文件字段\n            if (file != null) {\n                builder.addPart(\"file\", new FileBody(file, ContentType.create(contentType), fileName));\n            } else if (inputStream != null) {\n                builder.addPart(\"file\", new InputStreamBody(inputStream, ContentType.create(contentType), fileName));\n            }\n\n            httpPost.setEntity(builder.build());\n\n            HttpResponse response = AdminHttpUtils.getHttpClient().execute(httpPost);\n            int statusCode = response.getStatusLine().getStatusCode();\n\n            // 消耗响应体\n            if (response.getEntity() != null) {\n                EntityUtils.consumeQuietly(response.getEntity());\n            }\n\n            // 七牛云返回 200 表示成功\n            if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_CREATED) {\n                throw new Exception(\"文件上传到七牛云失败，HTTP状态码：\" + statusCode);\n            }\n\n            IMResult<String> imResult = new IMResult<>();\n            imResult.setCode(0);\n            imResult.setResult(presignedUrl.downloadUrl);\n            return imResult;\n        } finally {\n            httpPost.releaseConnection();\n        }\n    }\n\n    /**\n     * 上传到其他对象存储（type != 1）\n     * 使用 PUT + 二进制流\n     */\n    private static IMResult<String> uploadToOther(OutputPresignedUploadUrl presignedUrl, File file,\n                                           InputStream inputStream, String contentType) throws Exception {\n        HttpPut httpPut = new HttpPut(presignedUrl.uploadUrl);\n        try {\n            // 设置请求实体\n            if (file != null) {\n                FileEntity fileEntity = new FileEntity(file);\n                fileEntity.setContentType(contentType);\n                httpPut.setEntity(fileEntity);\n            } else if (inputStream != null) {\n                InputStreamEntity streamEntity = new InputStreamEntity(inputStream);\n                streamEntity.setContentType(contentType);\n                httpPut.setEntity(streamEntity);\n            }\n\n            HttpResponse response = AdminHttpUtils.getHttpClient().execute(httpPut);\n            int statusCode = response.getStatusLine().getStatusCode();\n\n            // 消耗响应体，确保连接可以被复用\n            if (response.getEntity() != null) {\n                EntityUtils.consumeQuietly(response.getEntity());\n            }\n\n            if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_CREATED) {\n                throw new Exception(\"文件上传失败，HTTP状态码：\" + statusCode);\n            }\n\n            IMResult<String> imResult = new IMResult<>();\n            imResult.setCode(0);\n            imResult.setResult(presignedUrl.downloadUrl);\n            return imResult;\n        } finally {\n            httpPut.releaseConnection();\n        }\n    }\n\n    /**\n     * 上传文件（通过输入流）\n     * <p>\n     * 流程：先调用getPresignedUploadUrl获取预签名上传地址，然后直接上传文件。\n     * 上传成功后返回文件的下载地址等信息。\n     * </p>\n     *\n     * @param inputStream 文件输入流\n     * @param fileName    文件名\n     * @return 上传结果，包含下载地址\n     * @throws Exception 上传失败时抛出异常\n     */\n    public static IMResult<String> uploadFile(InputStream inputStream, String fileName) throws Exception {\n        return uploadFile(inputStream, fileName, ProtoConstants.MessageMediaType.FILE, null);\n    }\n    /**\n     * 上传文件（通过输入流）\n     * <p>\n     * 流程：先调用getPresignedUploadUrl获取预签名上传地址，然后直接上传文件。\n     * 上传成功后返回文件的下载地址等信息。\n     * </p>\n     * <p>\n     * <b>注意：</b>无论上传成功还是失败，此方法都会关闭输入流。\n     * </p>\n     *\n     * @param inputStream 文件输入流（此方法会关闭该流）\n     * @param fileName    文件名\n     * @param mediaType   媒体类型，参考{@link cn.wildfirechat.proto.ProtoConstants.MessageMediaType}\n     * @param contentType 文件Content-Type，例如 \"image/jpeg\", \"application/octet-stream\" 等；\n     *                    如果为null或空，则根据文件名自动识别\n     * @return 上传结果，包含下载地址\n     * @throws Exception 上传失败时抛出异常\n     */\n    public static IMResult<String> uploadFile(InputStream inputStream, String fileName,\n                                       int mediaType, String contentType) throws Exception {\n        if (inputStream == null) {\n            throw new IllegalArgumentException(\"输入流不能为空\");\n        }\n\n        // 如果未指定Content-Type，根据文件名自动获取\n        if (contentType == null || contentType.isEmpty()) {\n            contentType = getContentTypeByFileName(fileName);\n        }\n\n        return doUploadFile(fileName, mediaType, contentType, null, inputStream);\n        // 注意：正常流程下的流关闭在 uploadToQiniu 或 uploadToOther 的 finally 块中处理\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/GenerateTestData.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.sdk.model.IMResult;\n\nimport java.io.BufferedWriter;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.ConcurrentSkipListSet;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * 生成测试数据。本应用生成以下数据：\n * 1. 创建${totalUserCount}个用户\n * 2. 每个用户同其他${friendCount}个用户建立好友关系\n * 3. 确保每个人都加入${smallGroupCount}个群组成员数为${smallGroupMemberSize}的小群组\n * 4. 确保每个人都加入${middleGroupCount}个群组成员数为${middleGroupMemberSize}的中群组\n * 5. 确保每个人都加入${bigGroupCount}个群组成员数为${bigGroupMemberSize}的大群组\n * 6. 把数据分片${splitFileCount}个保存在文件中\n *\n * 好友关系和群组关系都是随机生成，有可能会出现最后几个用户无法满足精确好友数或者群组数的问题，但绝大部分数据都能满足需求。\n */\npublic class GenerateTestData {\n    //IM服务Server API\n    private static String AdminUrl = \"http://10.206.0.5:18080\";\n    private static String AdminSecret = \"123456\";\n\n    private static int totalUserCount = 20000;\n\n    //每个用户的好友数\n    private static int friendCount = 100;\n\n    //每个用户拥有的小群数，和小群的大小。\n    private static int smallGroupCount = 100;\n    private static int smallGroupMemberSize = 20;\n\n    //每个用户拥有的中群数，和中群的大小。\n    private static int middleGroupCount = 100;\n    private static int middleGroupMemberSize = 100;\n\n    //每个用户拥有的大群数，和大群的大小。\n    private static int bigGroupCount = 20;\n    private static int bigGroupMemberSize = 1000;\n\n    //数据文件分割成几个文件存储。\n    private static int splitFileCount = 1;\n\n\n    //统计添加好友数和创建群组数。\n    private static AtomicInteger addFriendCount = new AtomicInteger(0);\n    private static AtomicInteger createGroupCount = new AtomicInteger(0);\n\n    public static void main(String[] args) throws Exception {\n        AdminConfig.initAdmin(AdminUrl, AdminSecret);\n        int addFriendRequestCount = friendCount*totalUserCount/2;\n        int createSmallGroupCount = smallGroupCount * totalUserCount / smallGroupMemberSize;\n        int createMiddleGroupCount = middleGroupCount * totalUserCount / middleGroupMemberSize;\n        int createBigGroupCount = bigGroupCount * totalUserCount / bigGroupMemberSize;\n        System.out.println(\"根据当前的参数，将创建 \" + totalUserCount + \" 名用户\");\n        System.out.println(\"添加大概 \" + addFriendRequestCount + \" 次好友请求\");\n        System.out.println(\"创建大概 \" + createSmallGroupCount + \" 个小型群组\");\n        System.out.println(\"创建大概 \" + createMiddleGroupCount + \" 个中等群组\");\n        System.out.println(\"创建大概 \" + createBigGroupCount + \" 个大型群组\");\n        System.out.println(\"等待10秒开始\");\n        Thread.sleep(10*1000);\n\n        List<String> userIds = generateUserIds(totalUserCount);\n\n        CountDownLatch latch = new CountDownLatch(5);\n\n        new Thread(() -> {\n            createUsers(userIds);\n            latch.countDown();\n        }).start();\n\n        Map<String, Integer> unfulfilledFriendMap = new HashMap<>();\n        new Thread(() -> {\n            addFriends(userIds, friendCount, unfulfilledFriendMap);\n            latch.countDown();\n        }).start();\n\n        Map<String, Set<String>> userSmallGroupMap = new HashMap<>();\n        Map<String, Integer> unfulfilledSmallMap = new HashMap<>();\n        new Thread(() ->{\n            for (String userId : userIds) {\n                createGroup(userId, userIds, userSmallGroupMap, smallGroupCount, smallGroupMemberSize, unfulfilledSmallMap);\n            }\n            latch.countDown();\n        }).start();\n\n        Map<String, Set<String>> userMiddleGroupMap = new HashMap<>();\n        Map<String, Integer> unfulfilledMiddleMap = new HashMap<>();\n        new Thread(() ->{\n            for (String userId : userIds) {\n                createGroup(userId, userIds, userMiddleGroupMap, middleGroupCount, middleGroupMemberSize, unfulfilledMiddleMap);\n            }\n            latch.countDown();\n        }).start();\n\n        Map<String, Set<String>> userBigGroupMap = new HashMap<>();\n        Map<String, Integer> unfulfilledBigMap = new HashMap<>();\n        new Thread(() ->{\n            for (String userId : userIds) {\n                createGroup(userId, userIds, userBigGroupMap, bigGroupCount, bigGroupMemberSize, unfulfilledBigMap);\n            }\n            latch.countDown();\n        }).start();\n\n        latch.await();\n\n        System.out.println(\"数据初始化结束，实际建立好友关系: \" + addFriendCount.get() + \" 条。\");\n        if (!unfulfilledFriendMap.isEmpty()) {\n            System.out.println(\"有部分用户没有建立\" + friendCount + \"个好友关系，分别是：\");\n            printUnfulfilledMap(unfulfilledFriendMap);\n        }\n\n        System.out.println(\"数据初始化结束，创建群组: \" + createGroupCount.get() + \" 个。\");\n        if (!unfulfilledSmallMap.isEmpty()) {\n            System.out.println(\"有部分用户没有建立\" + smallGroupMemberSize + \"个群组成员的群，分别是：\");\n            printUnfulfilledMap(unfulfilledSmallMap);\n        }\n        if (!unfulfilledMiddleMap.isEmpty()) {\n            System.out.println(\"有部分用户没有建立\" + middleGroupMemberSize + \"个群组成员的群，分别是：\");\n            printUnfulfilledMap(unfulfilledMiddleMap);\n        }\n        if (!unfulfilledBigMap.isEmpty()) {\n            System.out.println(\"有部分用户没有建立\" + bigGroupMemberSize + \"个群组成员的群，分别是：\");\n            printUnfulfilledMap(unfulfilledBigMap);\n        }\n\n\n        System.out.println(\"保存数据到\" + splitFileCount + \"个文件中。\");\n        for (int i = 0; i < splitFileCount; i++) {\n            String filePath = \"data\"+i+\".csv\"; // 文件路径\n            BufferedWriter writer = new BufferedWriter(new FileWriter(filePath));\n            int partSize = totalUserCount/splitFileCount;\n            for (int j = 0; j < partSize; j++) {\n                String userId = userIds.get(i*partSize+j);\n                writeDeviceInfo(writer, userId, 3);\n                Set<String> smallGroupIds = userSmallGroupMap.get(userId);\n                writeGroupIds(writer, smallGroupIds);\n                Set<String> middleGroupIds = userMiddleGroupMap.get(userId);\n                writeGroupIds(writer, middleGroupIds);\n                Set<String> bigGroupIds = userBigGroupMap.get(userId);\n                writeGroupIds(writer, bigGroupIds);\n            }\n\n            writer.close();\n        }\n\n        System.out.println(\"保存结束。\");\n    }\n\n    private static void printUnfulfilledMap(Map<String, Integer> map) {\n        if(map.isEmpty())\n            return;\n\n        map.forEach((s, integer) -> System.out.print(s + \":\" + integer + \" \"));\n        System.out.println();\n    }\n\n    private static void writeDeviceInfo(BufferedWriter writer, String userId, int platform) throws IOException {\n        writer.write(userId);\n        writer.write(\",\");\n        writer.write(UUID.randomUUID().toString());\n        writer.write(\",\");\n        writer.write(\"\"+platform);\n        writer.write(\"\\n\");\n    }\n\n    private static void writeGroupIds(BufferedWriter writer, Set<String> groupIds) throws IOException {\n        int writeCount = 0;\n        for (String bigGroupId : groupIds) {\n            writer.write(bigGroupId);\n            writeCount++;\n            if(writeCount < groupIds.size()) {\n                writer.write(\",\");\n            } else {\n                writer.write(\"\\n\");\n            }\n        }\n    }\n    private static void createGroup(String userId, List<String> userIds, Map<String, Set<String>> userGroupMap, int groupCount, int memberSize, Map<String, Integer> unfulfilledUserMap) {\n        Set<String> groupIds = userGroupMap.computeIfAbsent(userId, s -> new HashSet<>());\n        int i = 0;\n        while (groupIds.size() < groupCount){\n            PojoGroupInfo groupInfo = new PojoGroupInfo();\n            groupInfo.setTarget_id(UUID.randomUUID().toString());\n            groupInfo.setOwner(userId);\n            groupInfo.setName(\"Group_\"+userId+i++);\n            groupInfo.setType(2);\n            groupIds.add(groupInfo.getTarget_id());\n\n            List<String> memberCandidates = new ArrayList<>(userIds);\n            List<String> memberIds = new ArrayList<>();\n            memberIds.add(userId);\n\n            while (!memberCandidates.isEmpty() && memberIds.size() < memberSize) {\n                String memberId = memberCandidates.get((int)(Math.random()*memberCandidates.size()));\n                memberCandidates.remove(memberId);\n                if(memberId.equals(userId)) {\n                    continue;\n                }\n                if (memberIds.contains(memberId)) {\n                    continue;\n                }\n                Set<String> memberGroupIds = userGroupMap.computeIfAbsent(memberId, s -> new HashSet<>());\n                if(memberGroupIds.contains(groupInfo.getTarget_id()) || memberGroupIds.size() >= groupCount) {\n                    continue;\n                }\n                memberGroupIds.add(groupInfo.getTarget_id());\n                memberIds.add(memberId);\n            }\n\n            List<PojoGroupMember> members = new ArrayList<>();\n            for (String memberId : memberIds) {\n                PojoGroupMember member1 = new PojoGroupMember();\n                member1.setMember_id(memberId);\n                members.add(member1);\n            }\n\n            try {\n                IMResult<OutputCreateGroupResult> resultCreateGroup = GroupAdmin.createGroup(groupInfo.getOwner(), groupInfo, members, null, null, null);\n                if (resultCreateGroup != null && resultCreateGroup.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                    System.out.println(\"create group success\");\n                } else {\n                    System.out.println(\"create group failure\");\n                    System.exit(-1);\n                }\n            } catch (Exception e) {\n                System.out.println(\"create group failure:\" + e);\n                System.exit(-1);\n            }\n\n            createGroupCount.incrementAndGet();\n            if(memberIds.size() < memberSize) {\n                unfulfilledUserMap.put(userId + \"'s group \" + groupInfo.getTarget_id(), memberIds.size());\n                System.out.println(\"Error, can not find enough user to create group for user:\" + userId);\n            }\n        }\n    }\n\n    private static void addFriends(List<String> userIds, int count, Map<String, Integer> unfulfilledFriendMap) {\n        ConcurrentLinkedQueue<Pair<String, String>> toAddSet = new ConcurrentLinkedQueue<>();\n        Map<String, Set<String>> userFriends = new HashMap<>();\n        for (String userId : userIds) {\n            List<String> candidates = new ArrayList<>(userIds);\n            Set<String> currentUserFriends = userFriends.computeIfAbsent(userId, s -> new HashSet<>());\n            while (!candidates.isEmpty() && currentUserFriends.size() < count) {\n                String friendId = candidates.get((int) (Math.random()*candidates.size()));\n                candidates.remove(friendId);\n                if(friendId.equals(userId)) {\n                    continue;\n                }\n\n                if(!currentUserFriends.contains(friendId)) {\n                    Set<String> targetUserFriends = userFriends.computeIfAbsent(friendId, s -> new HashSet<>());\n                    if(targetUserFriends.size() < count) {\n                        currentUserFriends.add(friendId);\n                        targetUserFriends.add(userId);\n                        toAddSet.add(new Pair<>(userId, friendId));\n                    }\n                }\n            }\n            if (currentUserFriends.size() < count) {\n                unfulfilledFriendMap.put(userId, currentUserFriends.size());\n                System.out.println(\"Error, can not find enough user to add friend for user:\" + userId);\n            }\n        }\n        int threadNum = 5;\n        CountDownLatch latch = new CountDownLatch(threadNum);\n        for (int i = 0; i < threadNum; i++) {\n            new Thread(() -> {\n                while (true) {\n                    Pair<String, String> pair = toAddSet.poll();\n                    if(pair == null) {\n                        latch.countDown();\n                        break;\n                    }\n                    try {\n                        IMResult<Void> result = RelationAdmin.setUserFriend(pair.first, pair.second, true, null);\n                        if (result != null && (result.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS || result.getErrorCode() == ErrorCode.ERROR_CODE_ALREADY_FRIENDS)) {\n                            System.out.println(\"add friend success\");\n                            addFriendCount.incrementAndGet();\n                        } else {\n                            System.out.println(\"failure\");\n                            System.exit(-1);\n                        }\n                    } catch (Exception e) {\n                        System.out.println(\"failure:\" + e);\n                        System.exit(-1);\n                    }\n                }\n            }).start();\n        }\n        try {\n            latch.await();\n        } catch (InterruptedException e) {\n            System.out.println(\"failure:\" + e);\n            System.exit(-1);\n        }\n    }\n\n    private static String generateUserId(int index) {\n        return UUID.randomUUID().toString().replace(\"-\", \"\");\n    }\n\n    private static List<String> generateUserIds(int count) {\n        List<String> userIds = new ArrayList<>();\n        for (int i = 0; i < count; i++) {\n            userIds.add(generateUserId(i));\n        }\n        return userIds;\n    }\n\n    private static void createUsers(List<String> userIds) {\n        for (int i = 0; i < userIds.size(); i++) {\n            InputOutputUserInfo userInfo = generateUserInfo(userIds.get(i), i);\n            try {\n                IMResult<OutputCreateUser> resultCreateUser = UserAdmin.createUser(userInfo);\n                if (resultCreateUser != null && resultCreateUser.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                    System.out.println(\"Create user \" + resultCreateUser.getResult().getName() + \" success\");\n                } else {\n                    System.out.println(\"Create user failure\");\n                    System.exit(-1);\n                }\n            } catch (Exception e) {\n                System.out.println(\"Create user failure\");\n                System.exit(-1);\n            }\n        }\n    }\n\n    private static InputOutputUserInfo generateUserInfo(String userId, int index) {\n        InputOutputUserInfo userInfo = new InputOutputUserInfo();\n        //用户ID，必须保证唯一性\n        userInfo.setUserId(userId);\n        //用户名，一般是用户登录帐号，也必须保证唯一性。也就是说所有用户的userId必须不能重复，所有用户的name必须不能重复，但可以同一个用户的userId和name是同一个，一般建议userId使用一个uuid，name是\"微信号\"且可以修改，\n        userInfo.setName(userId);\n        userInfo.setMobile((11000000000L+index) + \"\");\n        userInfo.setDisplayName(\"User\"+index);\n\n        return userInfo;\n    }\n    static class Pair<K, V> {\n        K first;\n        V second;\n\n        public Pair() {\n        }\n\n        public Pair(K first, V second) {\n            this.first = first;\n            this.second = second;\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/GroupAdmin.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\n\nimport java.util.List;\n\n/**\n * 群组管理类\n * <p>\n * 提供群组管理相关的功能，包括：\n * <ul>\n * <li>群组的创建、解散、转移</li>\n * <li>群组信息修改</li>\n * <li>群组成员管理（添加、移除、踢出）</li>\n * <li>群组管理员设置</li>\n * <li>群组成员禁言</li>\n * <li>用户群组查询</li>\n * </ul>\n * </p>\n */\npublic class GroupAdmin {\n    /**\n     * 创建群组\n     * @param operator 操作者用户ID\n     * @param group_info 群组信息\n     * @param members 群组成员列表\n     * @param member_extra 成员额外信息\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 创建结果，包含群组ID\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputCreateGroupResult> createGroup(String operator, PojoGroupInfo group_info, List<PojoGroupMember> members, String member_extra, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Create_Group;\n        PojoGroup pojoGroup = new PojoGroup();\n        pojoGroup.setGroup_info(group_info);\n        pojoGroup.setMembers(members);\n        InputCreateGroup createGroup = new InputCreateGroup();\n        createGroup.setGroup(pojoGroup);\n        createGroup.setOperator(operator);\n        createGroup.setMember_extra(member_extra);\n        createGroup.setTo_lines(to_lines);\n        createGroup.setNotify_message(notify_message);\n\n        return AdminHttpUtils.httpJsonPost(path, createGroup, OutputCreateGroupResult.class);\n    }\n\n    /**\n     * 获取群组信息\n     * @param groupId 群组ID\n     * @return 群组信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<PojoGroupInfo> getGroupInfo(String groupId) throws Exception {\n        String path = APIPath.Group_Get_Info;\n        InputGetGroup input = new InputGetGroup();\n        input.setGroupId(groupId);\n\n        return AdminHttpUtils.httpJsonPost(path, input, PojoGroupInfo.class);\n    }\n\n    /**\n     * 批量获取群组信息\n     * @param groupIds 群组ID列表\n     * @return 群组信息列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<PojoGroupInfoList> batchGroupInfos(List<String> groupIds) throws Exception {\n        String path = APIPath.Group_Batch_Info;\n        return AdminHttpUtils.httpJsonPost(path, groupIds, PojoGroupInfoList.class);\n    }\n\n    /**\n     * 解散群组\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 解散结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> dismissGroup(String operator, String groupId, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Dismiss;\n        InputDismissGroup dismissGroup = new InputDismissGroup();\n        dismissGroup.setOperator(operator);\n        dismissGroup.setGroup_id(groupId);\n        dismissGroup.setTo_lines(to_lines);\n        dismissGroup.setNotify_message(notify_message);\n        return AdminHttpUtils.httpJsonPost(path, dismissGroup, Void.class);\n    }\n\n    /**\n     * 转让群组\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param newOwner 新群主用户ID\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 转让结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> transferGroup(String operator, String groupId, String newOwner, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Transfer;\n        InputTransferGroup transferGroup = new InputTransferGroup();\n        transferGroup.setGroup_id(groupId);\n        transferGroup.setNew_owner(newOwner);\n        transferGroup.setOperator(operator);\n        transferGroup.setTo_lines(to_lines);\n        transferGroup.setNotify_message(notify_message);\n        return AdminHttpUtils.httpJsonPost(path, transferGroup, Void.class);\n    }\n\n    /**\n     * 修改群组信息\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param type 修改信息类型（ModifyGroupInfoType）\n     * @param value 新值\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 修改结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> modifyGroupInfo(String operator, String groupId, /*ModifyGroupInfoType*/int type, String value, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Modify_Info;\n        InputModifyGroupInfo modifyGroupInfo = new InputModifyGroupInfo();\n        modifyGroupInfo.setGroup_id(groupId);\n        modifyGroupInfo.setOperator(operator);\n        modifyGroupInfo.setTo_lines(to_lines);\n        modifyGroupInfo.setType(type);\n        modifyGroupInfo.setValue(value);\n        modifyGroupInfo.setNotify_message(notify_message);\n        return AdminHttpUtils.httpJsonPost(path, modifyGroupInfo, Void.class);\n    }\n\n    /**\n     * 获取群组成员列表\n     * @param groupId 群组ID\n     * @return 群组成员列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputGroupMemberList> getGroupMembers(String groupId) throws Exception {\n        String path = APIPath.Group_Member_List;\n        InputGetGroup input = new InputGetGroup();\n        input.setGroupId(groupId);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputGroupMemberList.class);\n    }\n\n    /**\n     * 获取群组成员信息\n     * @param groupId 群组ID\n     * @param memberId 成员用户ID\n     * @return 群组成员信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<PojoGroupMember> getGroupMember(String groupId, String memberId) throws Exception {\n        String path = APIPath.Group_Member_Get;\n        InputGetGroupMember input = new InputGetGroupMember();\n        input.setGroupId(groupId);\n        input.setMemberId(memberId);\n        return AdminHttpUtils.httpJsonPost(path, input, PojoGroupMember.class);\n    }\n\n    /**\n     * 添加群组成员\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param groupMembers 要添加的成员列表\n     * @param member_extra 成员额外信息\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 添加结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> addGroupMembers(String operator, String groupId, List<PojoGroupMember> groupMembers, String member_extra, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Member_Add;\n        InputAddGroupMember addGroupMember = new InputAddGroupMember();\n        addGroupMember.setGroup_id(groupId);\n        addGroupMember.setMembers(groupMembers);\n        addGroupMember.setOperator(operator);\n        addGroupMember.setMemberExtra(member_extra);\n        addGroupMember.setTo_lines(to_lines);\n        addGroupMember.setNotify_message(notify_message);\n        return AdminHttpUtils.httpJsonPost(path, addGroupMember, Void.class);\n    }\n\n    /**\n     * 设置或取消群组管理员\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param groupMemberIds 成员用户ID列表\n     * @param isManager true-设置为管理员，false-取消管理员\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setGroupManager(String operator, String groupId, List<String> groupMemberIds, boolean isManager, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Set_Manager;\n        InputSetGroupManager addGroupMember = new InputSetGroupManager();\n        addGroupMember.setGroup_id(groupId);\n        addGroupMember.setMembers(groupMemberIds);\n        addGroupMember.setIs_manager(isManager);\n        addGroupMember.setOperator(operator);\n        addGroupMember.setTo_lines(to_lines);\n        addGroupMember.setNotify_message(notify_message);\n        return AdminHttpUtils.httpJsonPost(path, addGroupMember, Void.class);\n    }\n\n    /**\n     * 禁言或解禁群组成员\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param groupMemberIds 成员用户ID列表\n     * @param isMute true-禁言，false-解禁\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 禁言结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> muteGroupMemeber(String operator, String groupId, List<String> groupMemberIds, boolean isMute, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Mute_Member;\n        InputMuteGroupMember addGroupMember = new InputMuteGroupMember();\n        addGroupMember.setGroup_id(groupId);\n        addGroupMember.setMembers(groupMemberIds);\n        addGroupMember.setIs_manager(isMute);\n        addGroupMember.setOperator(operator);\n        addGroupMember.setTo_lines(to_lines);\n        addGroupMember.setNotify_message(notify_message);\n        return AdminHttpUtils.httpJsonPost(path, addGroupMember, Void.class);\n    }\n\n    /**\n     * 允许或禁止群组成员发言\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param groupMemberIds 成员用户ID列表\n     * @param isAllow true-允许，false-禁止\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> allowGroupMemeber(String operator, String groupId, List<String> groupMemberIds, boolean isAllow, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Allow_Member;\n        InputMuteGroupMember addGroupMember = new InputMuteGroupMember();\n        addGroupMember.setGroup_id(groupId);\n        addGroupMember.setMembers(groupMemberIds);\n        addGroupMember.setIs_manager(isAllow);\n        addGroupMember.setOperator(operator);\n        addGroupMember.setTo_lines(to_lines);\n        addGroupMember.setNotify_message(notify_message);\n        return AdminHttpUtils.httpJsonPost(path, addGroupMember, Void.class);\n    }\n\n    /**\n     * 踢出群组成员\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param groupMemberIds 要踢出的成员用户ID列表\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 踢出结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> kickoffGroupMembers(String operator, String groupId, List<String> groupMemberIds, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Member_Kickoff;\n        InputKickoffGroupMember kickoffGroupMember = new InputKickoffGroupMember();\n        kickoffGroupMember.setGroup_id(groupId);\n        kickoffGroupMember.setMembers(groupMemberIds);\n        kickoffGroupMember.setOperator(operator);\n        kickoffGroupMember.setTo_lines(to_lines);\n        kickoffGroupMember.setNotify_message(notify_message);\n        return AdminHttpUtils.httpJsonPost(path, kickoffGroupMember, Void.class);\n    }\n\n    /**\n     * 退出群组\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 退出结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> quitGroup(String operator, String groupId, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Member_Quit;\n        InputQuitGroup quitGroup = new InputQuitGroup();\n        quitGroup.setGroup_id(groupId);\n        quitGroup.setOperator(operator);\n        quitGroup.setTo_lines(to_lines);\n        quitGroup.setNotify_message(notify_message);\n        return AdminHttpUtils.httpJsonPost(path, quitGroup, Void.class);\n    }\n\n    /**\n     * 设置群组成员别名\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param memberId 成员用户ID\n     * @param alias 别名\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setGroupMemberAlias(String operator, String groupId, String memberId, String alias, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Set_Member_Alias;\n        InputSetGroupMemberAlias input = new InputSetGroupMemberAlias();\n        input.setGroup_id(groupId);\n        input.setOperator(operator);\n        input.setMemberId(memberId);\n        input.setAlias(alias);\n        input.setTo_lines(to_lines);\n        input.setNotify_message(notify_message);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 设置群组成员额外信息\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param memberId 成员用户ID\n     * @param extra 额外信息\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setGroupMemberExtra(String operator, String groupId, String memberId, String extra, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Set_Member_Extra;\n        InputSetGroupMemberExtra input = new InputSetGroupMemberExtra();\n        input.setGroup_id(groupId);\n        input.setOperator(operator);\n        input.setMemberId(memberId);\n        input.setExtra(extra);\n        input.setTo_lines(to_lines);\n        input.setNotify_message(notify_message);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 设置群组备注（用户个性化设置）\n     * @param userId 用户ID\n     * @param groupId 群组ID\n     * @param remark 备注内容\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setGroupRemark(String userId, String groupId, String remark) throws Exception {\n        return GeneralAdmin.setUserSetting(userId, 26, groupId, remark);\n    }\n\n    /**\n     * 获取群组备注（用户个性化设置）\n     * @param userId 用户ID\n     * @param groupId 群组ID\n     * @return 备注内容\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<String> getGroupRemark(String userId, String groupId) throws Exception {\n        IMResult<UserSettingPojo> imResult = GeneralAdmin.getUserSetting(userId, 26, groupId);\n        IMResult<String> result = new IMResult<>();\n        result.code = imResult.code;;\n        result.msg = imResult.msg;;\n        if(imResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            result.result = imResult.result.getValue();\n        }\n        return result;\n    }\n\n    /**\n     * 设置群组是否收藏（用户个性化设置）\n     * @param userId 用户ID\n     * @param groupId 群组ID\n     * @param fav true-收藏，false-取消收藏\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setFavGroup(String userId, String groupId, boolean fav) throws Exception {\n        return GeneralAdmin.setUserSetting(userId, 6, groupId, fav?\"1\":\"0\");\n    }\n\n    /**\n     * 检查群组是否收藏（用户个性化设置）\n     * @param userId 用户ID\n     * @param groupId 群组ID\n     * @return true-已收藏，false-未收藏\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Boolean> isFavGroup(String userId, String groupId) throws Exception {\n        IMResult<UserSettingPojo> imResult = GeneralAdmin.getUserSetting(userId, 6, groupId);\n        IMResult<Boolean> result = new IMResult<>();\n        result.code = imResult.code;;\n        result.msg = imResult.msg;;\n        if(imResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            result.result = \"1\".equals(imResult.getResult().getValue());\n        }\n        return result;\n    }\n\n    /**\n     * 获取用户的群组列表\n     * @param user 用户ID\n     * @return 用户所属的群组ID列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputGroupIds> getUserGroups(String user) throws Exception {\n        String path = APIPath.Get_User_Groups;\n        InputUserId inputUserId = new InputUserId();\n        inputUserId.setUserId(user);\n        return AdminHttpUtils.httpJsonPost(path, inputUserId, OutputGroupIds.class);\n    }\n\n    /**\n     * 根据成员类型获取用户的群组列表\n     * @param user 用户ID\n     * @param groupMemberType 群组成员类型列表（GroupMemberType）\n     * @return 用户所属的群组ID列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputGroupIds> getUserGroupsByType(String user, List</*ProtoConstants.GroupMemberType*/Integer> groupMemberType) throws Exception {\n        String path = APIPath.Get_User_Groups_By_Type;\n        InputGetUserGroupByType input = new InputGetUserGroupByType(user, groupMemberType);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputGroupIds.class);\n    }\n\n    /**\n     * 获取两个用户的共同群组\n     * @param user1 用户1的ID\n     * @param user2 用户2的ID\n     * @return 共同群组ID列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputGroupIds> getCommonGroups(String user1, String user2) throws Exception {\n        String path = APIPath.Get_Common_Groups;\n        StringPairPojo intput = new StringPairPojo(user1, user2);\n        return AdminHttpUtils.httpJsonPost(path, intput, OutputGroupIds.class);\n    }\n\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/Main.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.mesh.PojoDomainPingResponse;\nimport cn.wildfirechat.pojos.mesh.PojoSearchUserRes;\nimport cn.wildfirechat.pojos.mesh.PojoUserConferenceResponse;\nimport cn.wildfirechat.pojos.moments.CommentPojo;\nimport cn.wildfirechat.pojos.moments.FeedPojo;\nimport cn.wildfirechat.pojos.moments.FeedsPojo;\nimport cn.wildfirechat.pojos.moments.MomentProfilePojo;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.sdk.messagecontent.*;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport com.google.gson.GsonBuilder;\nimport io.netty.util.internal.StringUtil;\n\n\nimport java.util.*;\n\nimport static cn.wildfirechat.pojos.MyInfoType.Modify_DisplayName;\nimport static cn.wildfirechat.proto.ProtoConstants.ChannelState.*;\nimport static cn.wildfirechat.proto.ProtoConstants.SystemSettingType.Group_Max_Member_Count;\n\n/**\n * 野火IM Server SDK示例程序主类\n * <p>\n * 提供SDK功能演示的示例代码，包括：\n * <ul>\n * <li>用户管理操作</li>\n * <li>群组管理操作</li>\n * <li>消息发送操作</li>\n * <li>好友关系管理</li>\n * <li>朋友圈功能</li>\n * <li>机器人功能</li>\n * </ul>\n * </p>\n */\npublic class Main {\n    /** 是否为商业版服务器 */\n    private static boolean commercialServer = false;\n    /** 是否启用高级音视频功能 */\n    private static boolean advanceVoip = false;\n    /** 是否启用机器人朋友圈功能 */\n    private static boolean robotMomentsEnabled = false;\n    /** 是否启用朋友圈功能 */\n    private static boolean momentsEnabled = false;\n    /** 管理端口是18080 */\n    private static String AdminUrl = \"http://localhost:18080\";\n    /** 管理员密钥 */\n    private static String AdminSecret = \"123456\";\n\n    /** 机器人和频道使用IM服务的公开端口80，注意不是18080 */\n    private static String IMUrl = \"http://localhost\";\n\n\n    /**\n     * 程序主入口\n     * @param args 命令行参数，包括：adminUrl、adminSecret、imUrl、commercialServer、advanceVoip\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    public static void main(String[] args) throws Exception {\n        // 解析命令行参数\n        if (args.length == 5) {\n            // 从命令行参数获取配置信息\n            AdminUrl = args[0];\n            AdminSecret = args[1];\n            IMUrl = args[2];\n            commercialServer = Boolean.parseBoolean(args[3]);\n            advanceVoip = Boolean.parseBoolean(args[4]);\n        } else {\n            // 显示帮助信息或使用默认值\n            if(args.length == 1 && (args[0].equals(\"-h\") || args[0].equals(\"--help\") || args[0].equals(\"-help\"))) {\n                System.out.println(\"Usage: java -jar checker.jar adminUrl adminSecret imUrl commercialServer advanceVoip \\n      e.g. java -jar checker.jar http://192.168.1.80:18080 123456 http://192.168.1.80 false false\");\n                return;\n            }\n            System.out.println(\"Usage: java -jar checker.jar adminUrl adminSecret imUrl commercialServer advanceVoip \\n      e.g. java -jar checker.jar http://192.168.1.80:18080 123456 http://192.168.1.80 false false\");\n            System.out.println();\n            System.out.println();\n            System.out.println(\"Use default value: java -jar checker.jar http://127.0.0.1:18080 123456 http://127.0.0.1 false false\");\n        }\n\n\n        //admin使用的是18080端口，超级管理接口，理论上不能对外开放端口，也不能让非内部服务知悉密钥。\n        // 执行管理员API测试\n        testAdmin();\n\n        //测试解析数据库中消息内容\n        testReadMessageContentFromDB();\n\n        //计算消息分表\n        testMessageSharding();\n\n        //Robot和Channel都是使用的80端口，第三方可以创建或者为第三方创建，第三方可以使用robot或者channel与IM系统进行对接。\n        // 测试机器人功能\n        testRobot();\n        // 测试频道功能\n        testChannel();\n\n        //测试Mesh相关API，用于分布式IM。Mesh相关测试依赖环境，不具备测绘条件，注释掉。\n        //testMesh();\n    }\n\n\n    /**\n     * 管理员API测试总入口\n     * <p>\n     * 测试所有管理员功能，包括：\n     * <ul>\n     * <li>用户管理</li>\n     * <li>用户关系管理</li>\n     * <li>群组管理</li>\n     * <li>聊天室管理</li>\n     * <li>消息管理</li>\n     * <li>消息内容测试</li>\n     * <li>频道API测试</li>\n     * <li>通用API测试</li>\n     * <li>敏感词API测试</li>\n     * <li>设备管理测试(仅商业版)</li>\n     * <li>会议功能测试(仅高级音视频版)</li>\n     * <li>朋友圈功能测试(仅启用时)</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testAdmin() throws Exception {\n        //初始化服务API，使用管理员URL和密钥\n        AdminConfig.initAdmin(AdminUrl, AdminSecret);\n\n        // 执行各类管理员API测试\n        testUser();           // 用户管理测试\n        testUserRelation();   // 用户关系测试\n        testGroup();          // 群组管理测试\n        testChatroom();       // 聊天室测试\n        testMessage();        // 消息发送测试\n        testMessageContent(); // 消息内容编码测试\n        testChannelApi();     // 频道API测试\n        testGeneralApi();     // 通用API测试\n        testSensitiveApi();   // 敏感词API测试\n\n        // 商业版功能测试\n        if (commercialServer) {\n            testDevice();     // 设备测试(仅商业版)\n        }\n\n        // 高级音视频功能测试\n        if(advanceVoip) {\n            testConference(); // 会议功能测试(仅高级音视频版)\n        }\n\n        // 朋友圈功能测试\n        if (momentsEnabled) {\n            testMomentsApi(); // 朋友圈API测试\n        }\n\n        System.out.println(\"Congratulation, all admin test case passed!!!!!!!\");\n    }\n\n    //***********************************************\n    //****  用户相关的API\n    //***********************************************\n    /**\n     * 用户管理API测试\n     * <p>\n     * 测试以下功能：\n     * <ul>\n     * <li>创建普通用户</li>\n     * <li>创建和删除机器人</li>\n     * <li>获取用户信息（按用户名、手机号、用户ID、邮箱）</li>\n     * <li>批量获取用户信息</li>\n     * <li>更新用户信息</li>\n     * <li>获取用户IM Token</li>\n     * <li>用户封禁/解封</li>\n     * <li>检查用户在线状态</li>\n     * <li>销毁用户（慎用）</li>\n     * <li>获取所有用户列表</li>\n     * <li>获取在线用户数量和列表（仅商业版）</li>\n     * <li>获取用户会话信息（仅商业版）</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testUser() throws Exception {\n        // 创建用户信息对象\n        InputOutputUserInfo userInfo = new InputOutputUserInfo();\n        //用户ID，必须保证唯一性\n        userInfo.setUserId(\"userId1\");\n        //用户名，一般是用户登录帐号，也必须保证唯一性。也就是说所有用户的userId必须不能重复，所有用户的name必须不能重复，但可以同一个用户的userId和name是同一个，一般建议userId使用一个uuid，name是\"微信号\"且可以修改，\n        userInfo.setName(\"user1\");\n        userInfo.setMobile(\"13900000000\");\n        userInfo.setDisplayName(\"user 1\");\n\n        // 调用SDK创建用户\n        IMResult<OutputCreateUser> resultCreateUser = UserAdmin.createUser(userInfo);\n        if (resultCreateUser != null && resultCreateUser.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Create user \" + resultCreateUser.getResult().getName() + \" success\");\n        } else {\n            System.out.println(\"Create user failure\");\n            System.exit(-1);\n        }\n\n        // 创建机器人信息对象\n        InputCreateRobot createRobot = new InputCreateRobot();\n        createRobot.setUserId(\"robot1\");\n        createRobot.setName(\"robot1\");\n        createRobot.setDisplayName(\"机器人\");\n        createRobot.setOwner(\"userId1\");\n        createRobot.setSecret(\"123456\");\n        createRobot.setCallback(\"http://127.0.0.1:8883/robot/recvmsg\");\n        // 调用SDK创建机器人\n        IMResult<OutputCreateRobot> resultCreateRobot = UserAdmin.createRobot(createRobot);\n        if (resultCreateRobot != null && resultCreateRobot.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Create robot \" + resultCreateRobot.getResult().getUserId() + \" success\");\n        } else {\n            System.out.println(\"Create robot failure\");\n            System.exit(-1);\n        }\n\n        // 获取机器人信息\n        IMResult<OutputRobot> outputRobotIMResult = UserAdmin.getRobotInfo(\"robot1\");\n        if(outputRobotIMResult != null && outputRobotIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Get robot success\");\n        } else {\n            System.out.println(\"Get robot failure\");\n            System.exit(-1);\n        }\n\n        // 销毁机器人\n        IMResult<Void> destroyResult = UserAdmin.destroyRobot(\"robot1\");\n        if(destroyResult != null && destroyResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"success\");\n        } else {\n            System.out.println(\"destroy user failure\");\n            System.exit(-1);\n        }\n\n        // 通过用户名获取用户信息\n        IMResult<InputOutputUserInfo> resultGetUserInfo1 = UserAdmin.getUserByName(userInfo.getName());\n        if (resultGetUserInfo1 != null && resultGetUserInfo1.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (userInfo.getUserId().equals(resultGetUserInfo1.getResult().getUserId())\n                && userInfo.getName().equals(resultGetUserInfo1.getResult().getName())\n                && userInfo.getMobile().equals(resultGetUserInfo1.getResult().getMobile())\n                && userInfo.getDisplayName().equals(resultGetUserInfo1.getResult().getDisplayName())) {\n                System.out.println(\"get user info success\");\n            } else {\n                System.out.println(\"get user info by name failure\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"get user info by name failure\");\n            System.exit(-1);\n        }\n\n        // 通过手机号获取用户信息\n        IMResult<InputOutputUserInfo> resultGetUserInfo2 = UserAdmin.getUserByMobile(userInfo.getMobile());\n        if (resultGetUserInfo2 != null && resultGetUserInfo2.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (userInfo.getUserId().equals(resultGetUserInfo2.getResult().getUserId())\n                && userInfo.getName().equals(resultGetUserInfo2.getResult().getName())\n                && userInfo.getMobile().equals(resultGetUserInfo2.getResult().getMobile())\n                && userInfo.getDisplayName().equals(resultGetUserInfo2.getResult().getDisplayName())) {\n                System.out.println(\"get user info success\");\n            } else {\n                System.out.println(\"get user info by mobile failure\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"get user info by mobile failure\");\n            System.exit(-1);\n        }\n\n        // 通过用户ID获取用户信息\n        IMResult<InputOutputUserInfo> resultGetUserInfo3 = UserAdmin.getUserByUserId(userInfo.getUserId());\n        if (resultGetUserInfo3 != null && resultGetUserInfo3.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (userInfo.getUserId().equals(resultGetUserInfo3.getResult().getUserId())\n                && userInfo.getName().equals(resultGetUserInfo3.getResult().getName())\n                && userInfo.getMobile().equals(resultGetUserInfo3.getResult().getMobile())\n                && userInfo.getDisplayName().equals(resultGetUserInfo3.getResult().getDisplayName())) {\n                System.out.println(\"get user info success\");\n            } else {\n                System.out.println(\"get user info by userId failure\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"get user info by userId failure\");\n            System.exit(-1);\n        }\n\n        // 通过邮箱获取用户信息（允许用户不存在）\n        IMResult<OutputUserInfoList> userInfoListIMResult = UserAdmin.getUserByEmail(\"13900000001@139.com\");\n        if(userInfoListIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS || userInfoListIMResult.getErrorCode() == ErrorCode.ERROR_CODE_NOT_EXIST) {\n            System.out.println(\"getUserByEmail success\");\n        } else {\n            System.out.println(\"getUserByEmail failure\");\n            System.exit(-1);\n        }\n\n        // 批量获取用户信息\n        IMResult<OutputUserInfoList> batchGetUsers = UserAdmin.getBatchUsers(Arrays.asList(\"userId1\", \"admin\", \"FireRobot\", \"TestUser\"));\n        if (batchGetUsers.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get batch user success\");\n        } else {\n            System.out.println(\"get batch user failure\");\n            System.exit(-1);\n        }\n\n        // 准备更新用户信息（先测试不存在的用户ID）\n        InputOutputUserInfo updateUserInfo = new InputOutputUserInfo();\n        updateUserInfo.setUserId(System.currentTimeMillis()+\"\");\n        updateUserInfo.setDisplayName(\"updatedUserName\");\n        updateUserInfo.setPortrait(\"updatedUserPortrait\");\n        // 设置更新标志：更新显示名称和头像\n        int updateUserFlag = ProtoConstants.UpdateUserInfoMask.Update_User_DisplayName | ProtoConstants.UpdateUserInfoMask.Update_User_Portrait;\n        IMResult<Void> result = UserAdmin.updateUserInfo(updateUserInfo, updateUserFlag);\n        if(result != null && result.getErrorCode() == ErrorCode.ERROR_CODE_NOT_EXIST) {\n            System.out.println(\"updateUserInfo success\");\n        } else {\n            System.out.println(\"updateUserInfo failure\");\n            System.exit(-1);\n        }\n\n        // 更新存在的用户信息\n        updateUserInfo.setUserId(userInfo.getUserId());\n        result = UserAdmin.updateUserInfo(updateUserInfo, updateUserFlag);\n        if(result != null && result.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"updateUserInfo success\");\n        } else {\n            System.out.println(\"updateUserInfo failure\");\n            System.exit(-1);\n        }\n\n        // 验证用户信息是否更新成功\n        IMResult<InputOutputUserInfo> resultGetUserInfo4 = UserAdmin.getUserByUserId(userInfo.getUserId());\n        if (resultGetUserInfo4 != null && resultGetUserInfo4.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (userInfo.getUserId().equals(resultGetUserInfo4.getResult().getUserId())\n                && updateUserInfo.getDisplayName().equals(resultGetUserInfo4.getResult().getDisplayName())\n                && updateUserInfo.getPortrait().equals(resultGetUserInfo4.getResult().getPortrait())) {\n                System.out.println(\"get user info success\");\n            } else {\n                System.out.println(\"get user info by userId failure\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"get user info by userId failure\");\n            System.exit(-1);\n        }\n\n        // 获取用户的IM Token，用于客户端登录\n        IMResult<OutputGetIMTokenData> resultGetToken = UserAdmin.getUserToken(userInfo.getUserId(), \"client111\", ProtoConstants.Platform.Platform_Android);\n        if (resultGetToken != null && resultGetToken.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get token success: \" + resultGetToken.getResult().getToken());\n        } else {\n            System.out.println(\"get user token failure\");\n            System.exit(-1);\n        }\n\n        // 封禁用户（状态码：2表示封禁）\n        IMResult<Void> resultVoid =UserAdmin.updateUserBlockStatus(userInfo.getUserId(), 2);\n        if (resultVoid != null && resultVoid.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"block user done\");\n        } else {\n            System.out.println(\"block user failure\");\n            System.exit(-1);\n        }\n\n        // 检查用户封禁状态\n        IMResult<OutputUserStatus> resultCheckUserStatus = UserAdmin.checkUserBlockStatus(userInfo.getUserId());\n        if (resultCheckUserStatus != null && resultCheckUserStatus.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (resultCheckUserStatus.getResult().getStatus() == 2) {\n                System.out.println(\"check user status success\");\n            } else {\n                System.out.println(\"user status not correct\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"block user failure\");\n            System.exit(-1);\n        }\n\n        // 获取所有被封禁用户列表\n        IMResult<OutputUserBlockStatusList> resultBlockStatusList = UserAdmin.getBlockedList();\n        if (resultBlockStatusList != null && resultBlockStatusList.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            boolean success = false;\n            for (InputOutputUserBlockStatus blockStatus : resultBlockStatusList.getResult().getStatusList()) {\n                if (blockStatus.getUserId().equals(userInfo.getUserId()) && blockStatus.getStatus() == 2) {\n                    System.out.println(\"get block list done\");\n                    success = true;\n                    break;\n                }\n            }\n            if (!success) {\n                System.out.println(\"block user status is not expected\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"block user failure\");\n            System.exit(-1);\n        }\n\n        // 解封用户（状态码：0表示正常）\n        resultVoid =UserAdmin.updateUserBlockStatus(userInfo.getUserId(), 0);\n        if (resultVoid != null && resultVoid.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"block user done\");\n        } else {\n            System.out.println(\"block user failure\");\n            System.exit(-1);\n        }\n\n        // 再次检查用户状态，确认已解封\n        resultCheckUserStatus = UserAdmin.checkUserBlockStatus(userInfo.getUserId());\n        if (resultCheckUserStatus != null && resultCheckUserStatus.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (resultCheckUserStatus.getResult().getStatus() == 0) {\n                System.out.println(\"check user status success\");\n            } else {\n                System.out.println(\"user status not correct\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"block user failure\");\n            System.exit(-1);\n        }\n\n        // 检查用户在线状态\n        IMResult<OutputCheckUserOnline> outputCheckUserOnline = UserAdmin.checkUserOnlineStatus(userInfo.getUserId());\n        if (outputCheckUserOnline != null && outputCheckUserOnline.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"check user online status success:\" + outputCheckUserOnline.getResult().getSessions().size());\n        } else {\n            System.out.println(\"block user online failure\");\n            System.exit(-1);\n        }\n\n        //测试踢下线用户客户端\n        IMResult<Void> kickoffResult = UserAdmin.kickoffUserClient(userInfo.getUserId(), null);\n        if (kickoffResult != null && kickoffResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"kickoff user client success\");\n        } else {\n            System.out.println(\"kickoff user client failure\");\n            System.exit(-1);\n        }\n\n        //慎用，这个方法可能功能不完全，如果用户不在需要，建议使用block功能屏蔽用户\n        // 销毁用户（物理删除，不可恢复）\n        IMResult<Void> voidIMResult = UserAdmin.destroyUser(\"user11\");\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"destroy user success\");\n        } else {\n            System.out.println(\"destroy user failure\");\n            System.exit(-1);\n        }\n\n        // 获取所有用户列表（分页：每页100条，第0页）\n        IMResult<OutputGetUserList> getUserListIMResult = UserAdmin.getAllUsers(100, 0);\n        if (getUserListIMResult != null && getUserListIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"getUserListIMResult success\");\n        } else {\n            System.out.println(\"getUserListIMResult failure\");\n            System.exit(-1);\n        }\n\n        // 商业版专属功能\n        if (commercialServer) {\n            // 获取在线用户总数\n            IMResult<GetOnlineUserCountResult> getOnlineUserCountResultIMResult = UserAdmin.getOnlineUserCount();\n            if (getOnlineUserCountResultIMResult != null && getOnlineUserCountResultIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"get user online count success\");\n            } else {\n                System.out.println(\"get user online count failure\");\n                System.exit(-1);\n            }\n\n            // 获取在线用户列表（分页：第1页，从0开始，每页100条）\n            IMResult<GetOnlineUserResult> getOnlineUserResultIMResult = UserAdmin.getOnlineUser(1, 0, 100);\n            if (getOnlineUserResultIMResult != null && getOnlineUserResultIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"get user online success\");\n            } else {\n                System.out.println(\"get user online failure\");\n                System.exit(-1);\n            }\n\n            // 获取指定用户的会话信息\n            IMResult<GetUserSessionResult> getUserSessionResultIMResult = UserAdmin.getUserSession(\"hygqmws2k\");\n            if (getUserSessionResultIMResult != null && getUserSessionResultIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"get user session success\");\n            } else {\n                System.out.println(\"get user session failure\");\n                System.exit(-1);\n            }\n        }\n    }\n\n    //***********************************************\n    //****  用户关系相关的API\n    //***********************************************\n    /**\n     * 用户关系管理API测试\n     * <p>\n     * 测试以下功能：\n     * <ul>\n     * <li>发送好友请求</li>\n     * <li>设置好友关系</li>\n     * <li>获取好友列表</li>\n     * <li>解除好友关系</li>\n     * <li>黑名单管理</li>\n     * <li>好友备注（别名）管理</li>\n     * <li>好友额外信息管理</li>\n     * <li>获取好友关系详情</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testUserRelation() throws Exception {\n\n        //先创建2个用户用于测试好友关系\n        InputOutputUserInfo userInfo = new InputOutputUserInfo();\n        userInfo.setUserId(\"ff1\");\n        userInfo.setName(\"ff1\");\n        userInfo.setMobile(\"13800000000\");\n        userInfo.setDisplayName(\"ff1\");\n\n        // 调用SDK创建第一个用户\n        IMResult<OutputCreateUser> resultCreateUser = UserAdmin.createUser(userInfo);\n        if (resultCreateUser != null && resultCreateUser.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Create user \" + resultCreateUser.getResult().getName() + \" success\");\n        } else {\n            System.out.println(\"Create user failure\");\n            System.exit(-1);\n        }\n\n        // 创建第二个用户\n        userInfo = new InputOutputUserInfo();\n        userInfo.setUserId(\"ff2\");\n        userInfo.setName(\"ff2\");\n        userInfo.setMobile(\"13800000001\");\n        userInfo.setDisplayName(\"ff2\");\n\n        // 调用SDK创建第二个用户\n        resultCreateUser = UserAdmin.createUser(userInfo);\n        if (resultCreateUser != null && resultCreateUser.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Create user \" + resultCreateUser.getResult().getName() + \" success\");\n        } else {\n            System.out.println(\"Create user failure\");\n            System.exit(-1);\n        }\n\n        // 发送好友请求：ff1向ff2发送好友请求，附带问候语\"hello\"，直接设为好友\n        IMResult<Void> result = RelationAdmin.sendFriendRequest(\"ff1\", \"ff2\", \"hello\", true);\n        if (result != null && (result.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS || result.getErrorCode() == ErrorCode.ERROR_CODE_ALREADY_FRIENDS)) {\n            System.out.println(\"send friend request success\");\n        } else {\n            System.out.println(\"failure\");\n            System.exit(-1);\n        }\n\n        // 设置好友关系：ff1把ff2设为好友，并附带额外信息\n        IMResult<Void> updateFriendStatusResult = RelationAdmin.setUserFriend(\"ff1\", \"ff2\", true, \"{\\\"from\\\":1}\");\n        if (updateFriendStatusResult != null && updateFriendStatusResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"update friend status success\");\n        } else {\n            System.out.println(\"update friend status failure\");\n            System.exit(-1);\n        }\n\n        // 获取ff1的好友列表\n        IMResult<OutputStringList> resultGetFriendList = RelationAdmin.getFriendList(\"ff1\");\n        if (resultGetFriendList != null && resultGetFriendList.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && resultGetFriendList.getResult().getList().contains(\"ff2\")) {\n            System.out.println(\"get friend status success\");\n        } else {\n            System.out.println(\"get friend status failure\");\n            System.exit(-1);\n        }\n\n        // 解除好友关系：ff1删除ff2\n        updateFriendStatusResult = RelationAdmin.setUserFriend(\"ff1\", \"ff2\", false, null);\n        if (updateFriendStatusResult != null && updateFriendStatusResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"update friend status success\");\n        } else {\n            System.out.println(\"update friend status failure\");\n            System.exit(-1);\n        }\n\n        // 再次获取好友列表，确认ff2已被删除\n        resultGetFriendList = RelationAdmin.getFriendList(\"ff1\");\n        if (resultGetFriendList != null && resultGetFriendList.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && !resultGetFriendList.getResult().getList().contains(\"ff2\")) {\n            System.out.println(\"get friend status success\");\n        } else {\n            System.out.println(\"get friend status failure\");\n            System.exit(-1);\n        }\n\n\n        // 将ff2加入黑名单：ff1把ff2加入黑名单\n        IMResult<Void> updateBlacklistStatusResult = RelationAdmin.setUserBlacklist(\"ff1\", \"ff2\", true);\n        if (updateBlacklistStatusResult != null && updateBlacklistStatusResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"update blacklist status success\");\n        } else {\n            System.out.println(\"update blacklist status failure\");\n            System.exit(-1);\n        }\n\n        // 获取黑名单列表\n        resultGetFriendList = RelationAdmin.getUserBlacklist(\"ff1\");\n        if (resultGetFriendList != null && resultGetFriendList.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && resultGetFriendList.getResult().getList().contains(\"ff2\")) {\n            System.out.println(\"get blacklist status success\");\n        } else {\n            System.out.println(\"get blacklist status failure\");\n            System.exit(-1);\n        }\n\n        // 设置好友备注（别名）\n        String alias = \"hello\" + System.currentTimeMillis();\n        IMResult<Void> updateFriendAlias = RelationAdmin.updateFriendAlias(\"ff1\", \"ff2\", alias);\n        if (updateFriendAlias != null && updateFriendAlias.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"update friend alias success\");\n        } else {\n            System.out.println(\"update friend alias failure\");\n            System.exit(-1);\n        }\n\n        // 获取好友备注（别名）\n        IMResult<OutputGetAlias> getFriendAlias = RelationAdmin.getFriendAlias(\"ff1\", \"ff2\");\n        if (getFriendAlias != null && getFriendAlias.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && getFriendAlias.getResult().getAlias().equals(alias)) {\n            System.out.println(\"get friend alias success\");\n        } else {\n            System.out.println(\"get friend alias failure\");\n            System.exit(-1);\n        }\n\n        // 设置好友额外信息（可以存储自定义数据）\n        String friendExtra = \"hello friend extra\";\n        IMResult<Void> setExtraResult = RelationAdmin.updateFriendExtra(\"ff1\", \"ff2\", friendExtra);\n        if (setExtraResult != null && setExtraResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"set friend extra success\");\n        } else {\n            System.out.println(\"set friend extra failure\");\n            System.exit(-1);\n        }\n\n        // 获取好友关系详情（包括额外信息等）\n        IMResult<RelationPojo> getRelation = RelationAdmin.getRelation(\"ff1\", \"ff2\");\n        if (getRelation != null && getRelation.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get friend relation success\");\n        } else {\n            System.out.println(\"get friend relation failure\");\n            System.exit(-1);\n        }\n\n        // 验证好友额外信息是否正确\n        if(!friendExtra.equals(getRelation.getResult().extra)) {\n            System.out.println(\"set friend extra failure\");\n            System.exit(-1);\n        }\n\n        //测试获取用户的机器人列表\n        IMResult<OutputStringList> userRobotsResult = UserAdmin.getUserRobots(\"ff1\");\n        if (userRobotsResult != null && userRobotsResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get user robots success\");\n        } else {\n            System.out.println(\"get user robots failure\");\n            System.exit(-1);\n        }\n    }\n    //***********************************************\n    //****  群组相关功能\n    //***********************************************\n    /**\n     * 群组管理API测试\n     * <p>\n     * 测试以下功能：\n     * <ul>\n     * <li>创建群组</li>\n     * <li>获取群组信息</li>\n     * <li>转移群主</li>\n     * <li>修改群组信息（名称、扩展字段）</li>\n     * <li>获取群成员列表</li>\n     * <li>添加群成员</li>\n     * <li>踢出群成员</li>\n     * <li>设置群成员别名和扩展信息</li>\n     * <li>设置/取消群管理员（仅商业版）</li>\n     * <li>退出群组</li>\n     * <li>获取用户的群组列表</li>\n     * <li>获取共同群组</li>\n     * <li>群成员禁言/白名单管理（仅商业版）</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testGroup() throws Exception {\n\n        // 先解散可能存在的测试群组\n        IMResult<Void> voidIMResult1 = GroupAdmin.dismissGroup(\"user1\", \"groupId1\", null, null);\n\n        PojoGroupInfo groupInfo = new PojoGroupInfo();\n        groupInfo.setTarget_id(\"groupId1\");\n        groupInfo.setOwner(\"user1\");\n        groupInfo.setName(\"test_group\");\n        groupInfo.setExtra(\"hello extra\");\n        groupInfo.setType(2);\n        groupInfo.setPortrait(\"http://portrait\");\n        List<PojoGroupMember> members = new ArrayList<>();\n        PojoGroupMember member1 = new PojoGroupMember();\n        member1.setMember_id(groupInfo.getOwner());\n        members.add(member1);\n\n        PojoGroupMember member2 = new PojoGroupMember();\n        member2.setMember_id(\"user2\");\n        members.add(member2);\n\n        PojoGroupMember member3 = new PojoGroupMember();\n        member3.setMember_id(\"user3\");\n        members.add(member3);\n\n        IMResult<OutputCreateGroupResult> resultCreateGroup = GroupAdmin.createGroup(groupInfo.getOwner(), groupInfo, members, null, null, null);\n        if (resultCreateGroup != null && resultCreateGroup.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"create group success\");\n        } else {\n            System.out.println(\"create group failure\");\n            System.exit(-1);\n        }\n\n        IMResult<PojoGroupInfo> resultGetGroupInfo = GroupAdmin.getGroupInfo(groupInfo.getTarget_id());\n        if (resultGetGroupInfo != null && resultGetGroupInfo.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (groupInfo.getExtra().equals(resultGetGroupInfo.getResult().getExtra())\n                && groupInfo.getName().equals(resultGetGroupInfo.getResult().getName())\n                && groupInfo.getOwner().equals(resultGetGroupInfo.getResult().getOwner())) {\n                System.out.println(\"get group success\");\n            } else {\n                System.out.println(\"group info is not expected\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"create group failure\");\n            System.exit(-1);\n        }\n\n        IMResult<Void> voidIMResult = GroupAdmin.transferGroup(groupInfo.getOwner(), groupInfo.getTarget_id(), \"user2\", null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"transfer success\");\n        } else {\n            System.out.println(\"create group failure\");\n            System.exit(-1);\n        }\n\n        voidIMResult = GroupAdmin.modifyGroupInfo(groupInfo.getOwner(), groupInfo.getTarget_id(), ProtoConstants.ModifyGroupInfoType.Modify_Group_Name,\"HelloWorld\", null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"transfer success\");\n        } else {\n            System.out.println(\"create group failure\");\n            System.exit(-1);\n        }\n\n        voidIMResult = GroupAdmin.modifyGroupInfo(groupInfo.getOwner(), groupInfo.getTarget_id(), ProtoConstants.ModifyGroupInfoType.Modify_Group_Extra,\"HelloWorld2\", null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"modify group extra success\");\n        } else {\n            System.out.println(\"modify group extra failure\");\n            System.exit(-1);\n        }\n\n        resultGetGroupInfo = GroupAdmin.getGroupInfo(groupInfo.getTarget_id());\n        if (resultGetGroupInfo != null && resultGetGroupInfo.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (\"user2\".equals(resultGetGroupInfo.getResult().getOwner())) {\n                groupInfo.setOwner(\"user2\");\n            } else {\n                System.out.println(\"group info is not expected\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"create group failure\");\n            System.exit(-1);\n        }\n\n        IMResult<OutputGroupMemberList> resultGetMembers = GroupAdmin.getGroupMembers(groupInfo.getTarget_id());\n        if (resultGetMembers != null && resultGetMembers.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get group member success\");\n        } else {\n            System.out.println(\"create group failure\");\n            System.exit(-1);\n        }\n\n        PojoGroupMember m = new PojoGroupMember();\n        m.setMember_id(\"user1\");\n        m.setAlias(\"hello user1\");\n\n        voidIMResult = GroupAdmin.addGroupMembers(\"user1\", groupInfo.getTarget_id(), Arrays.asList(m), null, null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"add group member success\");\n        } else {\n            System.out.println(\"add group member failure\");\n            System.exit(-1);\n        }\n\n        IMResult<PojoGroupMember> groupMemberIMResult = GroupAdmin.getGroupMember(groupInfo.getTarget_id(), \"user1\");\n        if (groupMemberIMResult != null && groupMemberIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get group member success\");\n        } else {\n            System.out.println(\"get group member failure\");\n            System.exit(-1);\n        }\n\n        voidIMResult = GroupAdmin.kickoffGroupMembers(\"user1\", groupInfo.getTarget_id(), Arrays.asList(\"user3\"), null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"kickoff group member success\");\n        } else {\n            System.out.println(\"kickoff group member failure\");\n            System.exit(-1);\n        }\n\n        voidIMResult = GroupAdmin.setGroupMemberAlias(\"user1\", groupInfo.getTarget_id(), \"user2\", \"test user2\", null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"set group member alias success\");\n        } else {\n            System.out.println(\"set group member alias failure\");\n            System.exit(-1);\n        }\n\n        voidIMResult = GroupAdmin.setGroupMemberExtra(groupInfo.getOwner(), groupInfo.getTarget_id(), groupInfo.getOwner(), \"hello member extra2\", null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"set group member extra success\");\n        } else {\n            System.out.println(\"set group member extra failure\");\n            System.exit(-1);\n        }\n\n        if(commercialServer) {\n            PojoGroupMember m4 = new PojoGroupMember();\n            m4.setMember_id(\"user4\");\n            m4.setAlias(\"hello user4\");\n\n            PojoGroupMember m5 = new PojoGroupMember();\n            m5.setMember_id(\"user5\");\n            m5.setAlias(\"hello user5\");\n\n            voidIMResult = GroupAdmin.addGroupMembers(\"user1\", groupInfo.getTarget_id(), Arrays.asList(m4, m5), null, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"add group member success\");\n            } else {\n                System.out.println(\"add group member failure\");\n                System.exit(-1);\n            }\n\n            voidIMResult = GroupAdmin.setGroupManager(\"user1\", groupInfo.getTarget_id(), Arrays.asList(\"user4\", \"user5\"), true, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"set group manager success\");\n            } else {\n                System.out.println(\"set group manager failure\");\n                System.exit(-1);\n            }\n\n            voidIMResult = GroupAdmin.setGroupManager(\"user1\", groupInfo.getTarget_id(), Arrays.asList(\"user4\", \"user5\"), false, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"cancel group manager success\");\n            } else {\n                System.out.println(\"cancel group manager failure\");\n                System.exit(-1);\n            }\n        }\n\n        voidIMResult = GroupAdmin.quitGroup(\"user4\", groupInfo.getTarget_id(), null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"quit group success\");\n        } else {\n            System.out.println(\"quit group failure\");\n            System.exit(-1);\n        }\n\n        IMResult<OutputGroupIds> groupIdsIMResult = GroupAdmin.getUserGroups(\"user1\");\n        if (groupIdsIMResult != null && groupIdsIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (groupIdsIMResult.getResult().getGroupIds().contains(groupInfo.getTarget_id())) {\n                System.out.println(\"get user groups success\");\n            } else {\n                System.out.println(\"get user groups failure\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"get user groups failure\");\n            System.exit(-1);\n        }\n\n        groupIdsIMResult = GroupAdmin.getUserGroupsByType(\"user2\", Arrays.asList(ProtoConstants.GroupMemberType.GroupMemberType_Manager, ProtoConstants.GroupMemberType.GroupMemberType_Owner));\n        if (groupIdsIMResult != null && groupIdsIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get user groups by type success\");\n        } else {\n            System.out.println(\"get user groups by type failure\");\n            System.exit(-1);\n        }\n\n        groupIdsIMResult = GroupAdmin.getCommonGroups(\"user1\", \"user2\");\n        if (groupIdsIMResult != null && groupIdsIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get user common groups success\");\n        } else {\n            System.out.println(\"get user common groups failure\");\n            System.exit(-1);\n        }\n\n        //测试批量获取群组信息\n        IMResult<PojoGroupInfoList> batchGroupInfoResult = GroupAdmin.batchGroupInfos(Arrays.asList(groupInfo.getTarget_id()));\n        if (batchGroupInfoResult != null && batchGroupInfoResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"batch get group info success\");\n        } else {\n            System.out.println(\"batch get group info failure\");\n            System.exit(-1);\n        }\n\n        //测试群备注功能\n        String groupRemark = \"test group remark\";\n        IMResult<Void> setGroupRemarkResult = GroupAdmin.setGroupRemark(\"user1\", groupInfo.getTarget_id(), groupRemark);\n        if (setGroupRemarkResult != null && setGroupRemarkResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"set group remark success\");\n        } else {\n            System.out.println(\"set group remark failure\");\n            System.exit(-1);\n        }\n\n        IMResult<String> getGroupRemarkResult = GroupAdmin.getGroupRemark(\"user1\", groupInfo.getTarget_id());\n        if (getGroupRemarkResult != null && getGroupRemarkResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && groupRemark.equals(getGroupRemarkResult.getResult())) {\n            System.out.println(\"get group remark success\");\n        } else {\n            System.out.println(\"get group remark failure\");\n            System.exit(-1);\n        }\n\n        //测试收藏群功能\n        IMResult<Void> setFavGroupResult = GroupAdmin.setFavGroup(\"user1\", groupInfo.getTarget_id(), true);\n        if (setFavGroupResult != null && setFavGroupResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"set fav group success\");\n        } else {\n            System.out.println(\"set fav group failure\");\n            System.exit(-1);\n        }\n\n        Thread.sleep(1000);\n        IMResult<Boolean> isFavGroupResult = GroupAdmin.isFavGroup(\"user1\", groupInfo.getTarget_id());\n        if (isFavGroupResult != null && isFavGroupResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && isFavGroupResult.getResult()) {\n            System.out.println(\"is fav group success\");\n        } else {\n            System.out.println(\"is fav group failure\");\n            System.exit(-1);\n        }\n\n        //取消收藏\n        setFavGroupResult = GroupAdmin.setFavGroup(\"user1\", groupInfo.getTarget_id(), false);\n        if (setFavGroupResult != null && setFavGroupResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"cancel fav group success\");\n        } else {\n            System.out.println(\"cancel fav group failure\");\n            System.exit(-1);\n        }\n\n        //仅专业版支持\n        if (commercialServer) {\n            //开启群成员禁言\n            voidIMResult = GroupAdmin.muteGroupMemeber(\"user1\", groupInfo.getTarget_id(), Arrays.asList(\"user5\"), true, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"mute group member success\");\n            } else {\n                System.out.println(\"mute group member failure\");\n                System.exit(-1);\n            }\n            //关闭群成员禁言\n            voidIMResult = GroupAdmin.muteGroupMemeber(\"user1\", groupInfo.getTarget_id(), Arrays.asList(\"user5\"), false, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"unmute group member success\");\n            } else {\n                System.out.println(\"unmute group member failure\");\n                System.exit(-1);\n            }\n\n            //开启群成员白名单，当群全局禁言时，白名单用户可以发言\n            voidIMResult = GroupAdmin.allowGroupMemeber(\"user1\", groupInfo.getTarget_id(), Arrays.asList(\"user5\"), true, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"allow group member success\");\n            } else {\n                System.out.println(\"allow group member failure\");\n                System.exit(-1);\n            }\n\n            //关闭群成员白名单\n            voidIMResult = GroupAdmin.allowGroupMemeber(\"user1\", groupInfo.getTarget_id(), Arrays.asList(\"user5\"), false, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"unallow group member success\");\n            } else {\n                System.out.println(\"unallow group member failure\");\n                System.exit(-1);\n            }\n        }\n\n        //测试解散群组\n        IMResult<Void> dismissGroupResult = GroupAdmin.dismissGroup(\"user2\", groupInfo.getTarget_id(), null, null);\n        if (dismissGroupResult != null && dismissGroupResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"dismiss group success\");\n        } else {\n            System.out.println(\"dismiss group failure\");\n            System.exit(-1);\n        }\n\n        //验证群组已被解散\n        resultGetGroupInfo = GroupAdmin.getGroupInfo(groupInfo.getTarget_id());\n        if (resultGetGroupInfo != null && resultGetGroupInfo.getErrorCode() == ErrorCode.ERROR_CODE_NOT_EXIST) {\n            System.out.println(\"group dismissed verified\");\n        } else {\n            System.out.println(\"group dismiss verify failure\");\n            System.exit(-1);\n        }\n    }\n\n    //***********************************************\n    //****  消息相关功能\n    //***********************************************\n    /**\n     * 消息管理API测试\n     * <p>\n     * 测试以下功能：\n     * <ul>\n     * <li>发送单聊消息</li>\n     * <li>获取消息详情</li>\n     * <li>撤回消息</li>\n     * <li>删除消息（仅商业版）</li>\n     * <li>更新消息内容（仅商业版）</li>\n     * <li>广播消息（仅商业版）</li>\n     * <li>撤回广播消息（仅商业版）</li>\n     * <li>获取会话已读时间戳（仅商业版）</li>\n     * <li>获取消息投递状态（仅商业版）</li>\n     * <li>清除会话（仅商业版）</li>\n     * <li>群发消息</li>\n     * <li>撤回群发消息</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testMessage() throws Exception {\n        // 创建会话对象：目标用户ff2，会话类型为私聊\n        Conversation conversation = new Conversation();\n        conversation.setTarget(\"ff2\");\n        conversation.setType(ProtoConstants.ConversationType.ConversationType_Private);\n        // 创建文本消息内容并编码为MessagePayload\n        TextMessageContent textMessageContent = new TextMessageContent(\"Hello world\");\n        MessagePayload payload = textMessageContent.encode();\n\n        IMResult<SendMessageResult> resultSendMessage = MessageAdmin.sendMessage(\"ff1\", conversation, payload, null);\n        if (resultSendMessage != null && resultSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"send message success\");\n        } else {\n            System.out.println(\"send message failure\");\n            System.exit(-1);\n        }\n\n        IMResult<OutputMessageData> outputMessageDataIMResult = MessageAdmin.getMessage(resultSendMessage.result.getMessageUid());\n        if(outputMessageDataIMResult != null && outputMessageDataIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && outputMessageDataIMResult.getResult().getMessageId() == resultSendMessage.getResult().getMessageUid()) {\n            System.out.println(\"get message success\");\n        } else {\n            System.out.println(\"get message failure\");\n            System.exit(-1);\n        }\n\n        IMResult<String> stringIMResult = MessageAdmin.recallMessage(\"user1\", resultSendMessage.getResult().getMessageUid());\n        if (stringIMResult != null && stringIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"recall message success\");\n        } else {\n            System.out.println(\"recall message failure\");\n            System.exit(-1);\n        }\n\n        if (commercialServer) {\n            IMResult<Void> voidIMResult = MessageAdmin.deleteMessage(resultSendMessage.getResult().getMessageUid());\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"delete message success\");\n            } else {\n                System.out.println(\"delete message failure\");\n                System.exit(-1);\n            }\n\n            payload.setSearchableContent(\"hello world2\");\n            resultSendMessage = MessageAdmin.sendMessage(\"user1\", conversation, payload, null);\n            if (resultSendMessage != null && resultSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"send message success\");\n            } else {\n                System.out.println(\"send message failure\");\n                System.exit(-1);\n            }\n\n            payload.setSearchableContent(\"hello world3\");\n            voidIMResult = MessageAdmin.updateMessageContent(\"user1\", resultSendMessage.getResult().getMessageUid(), payload, true);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"update message success\");\n            } else {\n                System.out.println(\"update message failure\");\n                System.exit(-1);\n            }\n\n            IMResult<BroadMessageResult> resultBroadcastMessage = MessageAdmin.broadcastMessage(\"user1\", 0, payload);\n            if (resultBroadcastMessage != null && resultBroadcastMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"broad message success, send message to \" + resultBroadcastMessage.getResult().getCount() + \" users\");\n            } else {\n                System.out.println(\"broad message failure\");\n                System.exit(-1);\n            }\n\n            voidIMResult = MessageAdmin.recallBroadCastMessage(\"user1\", resultBroadcastMessage.result.getMessageUid());\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"Success\");\n            } else {\n                System.out.println(\"failure\");\n            }\n\n            //测试删除广播消息\n            IMResult<Void> deleteBroadCastResult = MessageAdmin.deleteBroadCastMessage(\"user1\", resultBroadcastMessage.result.getMessageUid());\n            if (deleteBroadCastResult != null && deleteBroadCastResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"delete broadcast message success\");\n            } else {\n                System.out.println(\"delete broadcast message failure\");\n            }\n\n            IMResult<OutputTimestamp> timestampResult = MessageAdmin.getConversationReadTimestamp(\"57gqmws2k\", new Conversation(0, \"admin\", 0));\n            if(timestampResult != null && timestampResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"Get conversation read time success\");\n            } else {\n                System.out.println(\"Get conversation read time failure\");\n            }\n\n            timestampResult = MessageAdmin.getMessageDelivery(\"57gqmws2k\");\n            if(timestampResult != null && timestampResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"Get message delivery success\");\n            } else {\n                System.out.println(\"Get message delivery failure\");\n            }\n\n            conversation = new Conversation();\n            conversation.setTarget(\"user1\");\n            conversation.setType(ProtoConstants.ConversationType.ConversationType_Private);\n            conversation.setLine(0);\n            IMResult<Void> clearConversationResult = MessageAdmin.clearConversation(\"user2\", conversation);\n            if (clearConversationResult != null && clearConversationResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"clear conversation success\");\n            } else {\n                System.out.println(\"clear conversation failure\");\n            }\n\n            //测试清空用户消息\n            IMResult<Void> clearUserMessagesResult = MessageAdmin.clearUserMessages(\"user1\", conversation, 0, System.currentTimeMillis());\n            if (clearUserMessagesResult != null && clearUserMessagesResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"clear user messages success\");\n            } else {\n                System.out.println(\"clear user messages failure\");\n            }\n        }\n\n        List<String> multicastReceivers = Arrays.asList(\"user2\", \"user3\", \"user4\");\n        IMResult<MultiMessageResult> resultMulticastMessage = MessageAdmin.multicastMessage(\"user1\", multicastReceivers, 0, payload);\n        if (resultMulticastMessage != null && resultMulticastMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"multi message success, messageid is \" + resultMulticastMessage.getResult().getMessageUid());\n        } else {\n            System.out.println(\"multi message failure\");\n            System.exit(-1);\n        }\n\n        IMResult<Void> voidIMResult = MessageAdmin.recallMultiCastMessage(\"user1\", resultMulticastMessage.result.getMessageUid(), multicastReceivers);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Success\");\n        } else {\n            System.out.println(\"failure\");\n        }\n\n        //测试删除多播消息\n        IMResult<Void> deleteMultiCastResult = MessageAdmin.deleteMultiCastMessage(\"user1\", resultMulticastMessage.result.getMessageUid(), multicastReceivers);\n        if (deleteMultiCastResult != null && deleteMultiCastResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"delete multicast message success\");\n        } else {\n            System.out.println(\"delete multicast message failure\");\n        }\n\n    }\n\n    //***********************************************\n    //****  发送各种消息。\n    //***********************************************\n    /**\n     * 消息内容编码测试\n     * <p>\n     * 测试各种类型消息的编码和发送：\n     * <ul>\n     * <li>文本消息</li>\n     * <li>语音消息</li>\n     * <li>图片消息</li>\n     * <li>视频消息</li>\n     * <li>位置消息</li>\n     * <li>文件消息</li>\n     * <li>动态表情消息</li>\n     * <li>链接消息</li>\n     * <li>名片消息</li>\n     * <li>提醒消息</li>\n     * <li>富通知消息</li>\n     * <li>流式文本消息</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testMessageContent() throws Exception {\n        // 设置发送者\n        String sender = \"userId2\";\n        // 创建会话对象\n        Conversation conversation = new Conversation();\n        conversation.setTarget(\"3ygqmws2k\");\n        conversation.setType(ProtoConstants.ConversationType.ConversationType_Private);\n\n        //测试发送文本消息\n        TextMessageContent textMessageContent = new TextMessageContent(\"测试文本消息\");\n        //消息转成Payload并发送\n        MessagePayload payload = textMessageContent.encode();\n        IMResult<SendMessageResult> resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null);\n        checkSendMessageResult(resultSendMessage);\n\n        //测试发送语音消息\n        SoundMessageContent soundMessageContent = new SoundMessageContent();\n        //语音文件时长，单位秒\n        soundMessageContent.setDuration(7);\n        //语音文件格式为amr或者mp3，需要先上传到对象存储服务。\n        soundMessageContent.setRemoteMediaUrl(\"https://media.wfcoss.cn/firechat/voice_message_sample.amr\");\n        //消息转成Payload并发送\n        payload = soundMessageContent.encode();\n        resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null);\n        checkSendMessageResult(resultSendMessage);\n\n        //测试发送图片消息\n        ImageMessageContent imageMessageContent = new ImageMessageContent();\n        //base64edData为图片的缩略图。缩略图的生成规则是，把图片压缩到120X120大小的方框内，45%的质量压缩为JPG格式，再把二进制做base64编码得到字符串。\n        String thumbnailBase64edData = \"/9j/4AAQSkZJRgABAQAASABIAAD/4QCARXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAKgAgAEAAAAAQAAAHigAwAEAAAAAQAAAFoAAAAA/+0AOFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAAOEJJTQQlAAAAAAAQ1B2M2Y8AsgTpgAmY7PhCfv/AABEIAFoAeAMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2wBDAAcHBwcHBwwHBwwRDAwMERcRERERFx4XFxcXFx4kHh4eHh4eJCQkJCQkJCQrKysrKysyMjIyMjg4ODg4ODg4ODj/2wBDAQkJCQ4NDhkNDRk7KCEoOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozv/3QAEAAj/2gAMAwEAAhEDEQA/APaXJHFIiMTk1UN0EYBuM1Qn8QW9tM0EincpUDGCDuOPz9q9B6HGa15f2mnW7T3L4VcAgDJ59hXnLeMYU1K6lChInTAbd9/bgA+xxnFcN4r8RXUlzLJGS0BJ75Iz2bHTGQOvFcBcC/EIfnBPfnj8M1xznNv3eh006EppuKbtv5Hdvrs9vMs6KrYbKHOcAd8HgcelUzqlvIrvaB1kI4IPAPr07e1cBI928aKoY+oPXJPYd6tQ3D4lliHEZB2j0Oc4HcDvzXM0x2OtTWL+C38gzrIEbIKkknd1/D1qOe9d5knjkUM/8KcA9MkkVmwyXMjIiq0QXjO3+HqDk4GKoxTRvJ5NuCvJPzZ60khHR3FyyL84Ksx3FcYB/E1VeeJyN3yHGEzznPvWfdzmVCZo2ZsDbjJwe/1FZcPmXUirGCSvPHt9aajcpJvRHQtqd3a3Xkwncy/Kq5yDwfTrWfE8qXQilAUMpKsMEdP5djVZoYkzcSswlyMdAB7EYzWpbvaGNVbDSeWVZBwG+YtnkfT8quMW9EdEMJVm2lEtLEsEbLMzAHD5XJ49OeM+9Qx3cMFwqrGSoI+UH0z361l3V3cW8+wABZBkKeMA/WrEN3Ldh0gQhQPnYAYGPeoafUwaa0Ztf2hbeaPNUovLDyxlsnnk+vepP7Vs/wC/dfmP/iayBfSLK0ICyK4xjswNLtH/AD5r/n8aQj//0MhfFmvRTGSeTfESd0bYbg9s47VgnUme7a/kIaQ5+Y8feGO2M47Vjf6NNzE5jlPOATkfWoXgs4Iw967Su3ccfpXfJpo+z+q4e13SjZ9en+f4fMnuxErKr7iGHy4OFJxyc0tqgj6Ekd17VGk9nFASuXVjwCc/zppj0xQD5RVj/dJx/OslCKd00ONGjSd4cq+b/Prckms4ZkC7CFzwQeKhOm20GDEjsfXPenokGNolIB4K54/A4zVpBCytFltuMU1CLVrGscJRcb+zX4f195XiaI27RgtEoypAPOM9MnpVeM2lirMImO48ZIJHHTNSpbEPsll+Tk4LgZqG8sozhQ/l9gG5H5io5ZRV4o4J0ORe0pU1db3t+Ww19ZeNiV71Yt9T+1ht4SMKOST1zWeq2dupimTzDkZJ5HPpjGKvSw2caNGrRqrcjHHTpmnCU+sjTCTxC1c1pui20jPHutSJB3XA6/jVKTeylmCsxOMKDn8RUls0U6hreUxue3UGnz/bIwZGI8vGX9eKqUOeF2a4uEa9Lne3lr/wSQ2yRYjmQOV4O7BK57c1Ygt1tojDbq5DHJxk4PTtWT9oEkIWRtueg/8AsupoAuLVjJBKdvBbPPT2qeeL2RMuWMVONNSt100/X+uhpu/kqSZs7BglTnb36VW/tJP+ftv++azobpLgNLPIEMnynaB/KnfZ7P8A57t/3xRGSer/AK/EwhV54qWj9bf5n//R81axtSgjt3PmpyzA9c/Sq32a1ClLmUyYHG7ggfXvWlc6TpdzF5mn+fDMvDLtOB9ST/KsyHTJYDJvJlc7SCP4evXrx0zXTOKpPkSTflr+B9Iq9KhpGF7+d/wCOz2KRbmN4z/eHzE/XpS/2SqbZS7xlhymAxGfQg9PwqxpltYIry3d2YpQxMYAyOO+MdzVxpIYUFxcfPEASHQfMx7cZ/A1rTpc8HJq/wA9v1N4PDVqfM47bK/+WqKcVvbBRBcyCQdNpGxhjpUYew09jC6GTP8AE3zHjtmoWitNTj8mFtkiZID8ED69arR6XNiQTAEZ/h5NJxlFJxXz3NFWlOalRhd9916alz7Rp1xiN1A569MVE2mxXMRFrL15IasFAQz7QWAyoB4NWbM3MNyse7y3bsew9DXOqnM7TRxLGQry5K9O99LrQltY3sZzJcBUIONhzkj/AGcVbmntZHfy4DJ0zyMCtdrYylZZSX25x+NZ8ltbo+1m+UMSoA28n1IrWcHBWjsd31OtQiqdJJxv1tf1108tikbqZYAtqG2g8/L0/Gr1i2oSBmYlUzghhz64xRJOzDy4MJs54PAFNfUGyI5Q6NkkMemMVnezvcq6oyUpTdlpbp+ZLcW9tcnYYAW9QSKrQXF3atsmh2Rjjb2+uBVo3wkjw7nevHPWmSJNdw+T5m09QT1//VWz97WO5vJRk/aU/i8ra+pVu7WOVRdFGVWxt4/DNUfsy+r/AJCrIsL1oiqygtGBmNjx1/XNR/YNS/55Q/kKxlGTd0jxq/PUlzey/D/gn//S88sNclsj9kuQJywIU7iv51jXV/fSyyyxkgnoAMenX6c061RGu0mkbIC7sepHY1s6PDo5yb9s7+4yQCevAPNaRxFWclBztY64V6tXlhz2scqI7hkVmzmQkAgZHNKUu9OnUSYZ1yMZyOR/L3ro7q7ijlaGyV1RR0PTIJHFZ4njkvGnvMyBCAVHAIGe/XP49KyV4T0fzMVeE7X+ZltqtxLObkKufu4Udj6d62LYXtzulY+WTzg8Gpr+70UIjaZA0DAjd6cjn8qrzX9vEomjbcfvFSOfpXZopNzlc9/LqijzOrUul2f4lC4aSJzDMQgBz5mDyc+1SKIVeRiRcbssc/wmq2oXr6g6pCm0McFR79OuafFCtjI5KEqw2/NjjPsP51zzmlLTUxniF7VziuaK0T7fp95p3D3ctqJo/l2AYC9PX6fSsR7mK8j8olhJ1w3qK6C2sfOh3W7Ocg9MkKR6k8dPeq7W0VoyytCd46spyGHfNVCEWvd2R6MsNNxSg7R2fX+mY9taNG5aXDKwx9OnNdINs8JiuNvuO/4dQKgmksmAVImZpFHK8EZz2H0qIR3CLksdvXHce9XC0dYu6DDYanBy9m+ZPz/MtS3NskezyVQjAD425/Ko54HnGBOEZOduOR+NUtRlYLHCz7vMcAkjn8KmTULdIvK8hQVBJfOMjPAI7k1VSveT5rbf0tP1Mq2MhSqOjLb7vyJl8mbbBMG7KWX72TVn+yLH1uv8/wDAqzrLUIr35bgqhUgA8j8eOa1dlr/z8r+b/wCFTeNk/wCvyZ0wjSrRVRJO/ff9T//T8esX8mRH3ImCRx2IH5c+lW7q4Et/GGjAdXIO0cHt+ZOaoixaGF2Ygk7QrA9CT2Her0bXQgjYzfOxZQ7YIyOgrF1Wk430Y/aSUHFPRkf2oRXIS443AsDjnrnjFUDKyTOQcru/zn3q9PNdQxRB0xJtyz4554x+VQmM3aRRwKm6RwnXHJOM9M0RSS5mb0sLKpFtbpXt3RmMJriQx243FjwijmuuufBGp2FkdRupo9iIHdM4IGOe3PpXT6T4MutEv01AulyACJUxg4PdTz+PTitbxVYX+q2P2OxUNk/MoPbtk/WvDrZsnWhCjJcvVnbTwDhTlOotVsjyUXenKMRwjJq5HfWd3GI/KQsDyc447Vm3ej3enwTSXRSOSBgpiY4c7u4HcCse2/djeTzmvoYV+b3ovQuObVIe7OKt2tY9S0/xWdBtJLGZRIm8lCMHBPBBPpXOz34NzIWJdJc7eyjvj0rj5nmGVmPOcD8PSrtusrTLbqco/wB4kY7Z/SsKWHhTqyq0lZy/EmOZ1HWvS27GvHqUVsxVY8noSpyCKmF8rMrygqr7sY9uO9VW0o2qlySVdcg9OP8ACqxtJFZY/vjt7Cumc5RWp318VjKEFJrRboZeXcM0wQj5QnHsTWvoGm2V7b3U+ond5ATCAkN8x+9x1FMk0KCUC5dyOOSMYOOw96ptZxWMhubaVjxgg4zzWNam6kG4y+5nC8NWbeKqJSXWzX9aHc6f4G0iSFdRt7wvglkVwMD2YHritT/hH0/572f/AH6X/GuDnW4uIGM0xBYY2jjPHXAGMVi/2Wf+ex/KuGOX4uV3Gtp6I7pYbl+CkmvU/9Tze11H7JJ9khjAjkI+V0ByBjHHen6guizKpH7pmb+A4UH3Hb/61T+I4400awlRQHYnLAcnhepp3jK3t4I7byI1TkfdAH8q8yUbyjJO1xuRhNdGGJrYBX77/vfgPY1Whv4LNylpAFfPzTMNzZ9s8D8qpZOY/wDfSk1XjUZwOBvrrkvae7LY1q4qpUspPbY7i08cX1vqEb3W2aKNcOq8ZBHX3NaV547lEsdzp0DRRcgmQcN9MV5Y/UfSvSL1V/4RaE46JFj9K8jE4LDQnBuG+h2YbE1ZQm3LZXOY1vVk1OV55QJZXAwemMCuVKlMsa0JBgZHvUOAQQR/DmvZo01CCjHY8+Tcm5PqVchssRk8c0PNIJBLGfp6VpWgH2u046yL/MV1Xje3t4Vt5Io1RnJ3FQATwOtVe0khxhpzIhOmanHpSaj8ssbRCQgcttYc5B/u/wD16htPD99dpHeJLHEkynapJz7A+meua9BsgPIs17GJQR7FaoQACGADoEGP++RXl1cwnyyVtjWripygoSd0ctaaBqws2v3ysq7tsHO7aDg/j7d66Oy0G0uNJY3yfvlJDKRtZeOB71068zMTz8g/9Bp12ALqBRwDt4rlqYqdRcl7ddPyLp4qUKfK9VfY8VsxqCRiYRPNbglQDkg9emDnjrxVz7U//Pg35S//ABVes4CzOq8AR9B9ajrtWN1a5Tpoykly32P/2Q==\";\n        imageMessageContent.setThumbnailBytes(Base64.getDecoder().decode(thumbnailBase64edData));\n        //图片地址，发送前需要先上传到对象存储服务。\n        imageMessageContent.setRemoteMediaUrl(\"https://media.wfcoss.cn/firechat/image_message_sample.jpg\");\n        //消息转成Payload并发送\n        payload = imageMessageContent.encode();\n        resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null);\n        checkSendMessageResult(resultSendMessage);\n\n        //测试发送视频消息\n        VideoMessageContent videoMessageContent = new VideoMessageContent();\n        //base64edData为视频的首帧的缩略图。缩略图的生成规则是，把图片压缩到120X120大小的方框内，45%的质量压缩为JPG格式，再把二进制做base64编码得到字符串。\n        thumbnailBase64edData = \"/9j/4AAQSkZJRgABAQAASABIAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAAESgAwAEAAAAAQAAAHgAAAAA/8AAEQgAeABEAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/bAEMABwcHBwcHDAcHDBIMDAwSGBISEhIYHhgYGBgYHiQeHh4eHh4kJCQkJCQkJCwsLCwsLDMzMzMzOTk5OTk5OTk5Of/bAEMBCQkJDw4PGQ4OGTwpISk8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PP/dAAQABf/aAAwDAQACEQMRAD8Ab/wjfiDRJLuGK4g/0qFH8tS4LGPIwpXHIH8684vLq8ijktHBjcqVbqCcg/0r0PUo/NSy03cvmyKQ7uoXGRlRuyeB04pdW0HT4oWZ2NyjIkjbUwdpOfkbgZ7cc8GnuTY89sbu4l0xbdU3IVXocHKnGfrUV5aG6tnv0ZVmj5kTpuA7n3qnbyT+R5S/NHC+Adoz7e/StnUAzRRXEMYQOCCBn5vf0/KptqIyY3M0aEjBIAG0c/U4q7CDav58TKwKkYbjPqCK63R9HhuLhVtVMe+BXD8hA4z7Y5xitOPwp9p0qS8mBjlwCgYjB/2s8mnyhY8z+1AnZImAx6DjI9K257a50y1hitym53EiPGwLfMMYyPSruteGZdLtRI+DKMZAxgA/StDR7lYLuMX0ZEKYxsUFs9sfWhIDotEfUpLeR78M7mTgsMErtXFbOJP7h/IV0sMqXBkk8lfvY+Zueg681PiP/njH/wB9/wD16odj/9CK3jmaRL2Z40KyFRAqZViSOOhIzjPI4rZ1HTjdXsgMEayrH5zIpZ1LnjaDwAGznjkE1y8c1/FeGaNdsRbarKTgAnIXPr06Y9+9dde6xNb+HZjBGq3kTkkELkKMkNxnjjsaEScRoulylb+Zk3iGQAx5IyrnY+AOThuDg9q6u78K20a7NMdZpgwURHIQBiPmAPH1OcVT03R73SraLWplzDB5ZcHDCRJGy5b6cHFdxqGkTwpPqNhPsaTB3OSQFXsB04GcfWrA57SrSSNLq22iGaEArsZgGB+9kr1x6V29noVu0DsG2pcKCFUDC5Azg47motEhtElaZMMq5Eci8Ixb7+OfUd66Tzk42/yP6UAeeX+mWWmSSQy7bkzRkv52VRVQZGDzycetebrd3WmWyyLJsdsbR/Ft6gj2r2e9hvZ3kkuU3QK42oeSR7Y9feuQv9B0XT3dE3PcStuXJGEz228cfyoYEujWVxf28l40WDK+7o3PyjnrWv8A2NN/zz/8db/Gm6BfXt3YkyuqmNynT0A9a2/Muf8Anqv/AHyKQz//0b1zYsl5JHb3ZlwjSorqeCueOflyTz71gXh1y+Kx3Kr5lzgMMjPlgAnIHIGB1xirmk+KoLDZPbEtKqhJAUAyB2B/mT1xmuy8OWg1yW81yVfszTARIq8FQDk5xjqcfhimhG9o1rc3WlfYNTwrJ8pAxyuOPbGKtjw9AFMKTzLbnP7oMNo5zxkEgD0HFXbKxjtxyNzL/F+A6fiK0iaoDBtbafSwIConhGBG4AUr6hgB+oH1rZjJcbzx7U7NMOVJYdD1FADbhwifdLHPAHc1w96VtL6S7vjE7LHvKgY2nsMn/Gu9ODyaz73T7a+ieK5Xcrdun8qAM3QX1a4sjcC4OJHLYVeBkDgcVtbdW/5+G/75H+FZOjXMltaG1t7MskLlAQfT681q/b7v/nyb9P8AGgD/0syDwu0sctxbkCOMDiXClj3U84Iz3zycjtXp3hZpE0eK0mV0O3zAyAlSM8DPr6iuP0DSri9Z5bqEwqu1/MLEKCxyMDk5GSRk/X1r1jTraa0tzFNJ5nJIPPA7DnmmIuIW3MW74Ip5NNzTSaYCk01j8poNJ1FMB+ahmRpYyisUJ7in0ZoETQuqJtbk/hUvmp/nFRRRRMpLAZz6VJ5MP90flSGf/9P0Xw417JLdS3SL5YYCKQDaWHOcj8sGuqzXH6RqWi2FjHaw3OQvPzbifXnrituLWNOmTzEuEx05OD+RpiNTNJmsW513TbU7XlDH/Y+b+VTQatp9xtEU6kt0BOD+RoC5pE0ZrPudSsrZS00oGOCByfyFFtqNndpuhcH2PB/I0wuX80maz5NUsIpPKkmUN6VaeaKNd7uoHqTQIvw/c/GpqzbS/s5YtyyjGTVn7Va/89V/OgZ//9TDjmwfmrVtrK6vF3wKCAcZLAfzNUI0kZtwAH4f/Wrb09HiiIA6tVNmaRQkL2zNDIcFTyB0oW5IOetW7m3kM5l6Emnx2lxIevWgmxAbot1qY3LBVb1qZtNuFGdvT3qhcX1tazJY3ThWbnOen1pNjSbJTcsetL9oY9ya1JLG5jQFuFUZzU39lTyASDB3c565qtBWNLQZs2bnn/WH+Qrb8361U0WxmS1ZT/fP8hWx9jmqR2P/1eui023AG1MVejsoQuAtWVBHBxxUoyBTJKj2cRbO2rMVrGDnFSZGOetSqcc0CK13GI7eSRVB2qW59RzXzDLqiXV3DLdqeHzKVPLZbPHpgcV9QX2Xs5xnrG38q+Qm/wBcF9TVRQmz6luNY0v+wzq6fvLYrwO/pj61V8Iaomr6WzKhRInKKCckL1Az7dK52+Wy0nRE8O2+XR03sScnLHP4Vq+AYYYNMmEXTzOn4ClYo9J06JfJbj+L+grQ8pfSqVj/AKo/739BVykI/9b0IPx6GnhmHNQHrU/8NMgeGNSBgO+ahFC0ATz4aF19VI/SvkC5Hl3Deoavr6T7jfQ/yr5Dv/8Aj6f/AHquImfR15JDP4WhvZdit5Me5247Acmuf8Da3DJfXGmIQwI3Aj1GAcVb1T/knv8A2xj/AKVwnw4/5GFv91v6UlsUz6W05/3Lf739BV/dWZpv+pb/AHv6CtCkI//Z\";\n        videoMessageContent.setThumbnailBytes(Base64.getDecoder().decode(thumbnailBase64edData));\n        //视频时长，单位秒\n        videoMessageContent.setDuration(3);\n        //视频地址，发送前需要先上传到对象存储服务。\n        videoMessageContent.setRemoteMediaUrl(\"https://media.wfcoss.cn/firechat/video_message_sample.mov\");\n        //消息转成Payload并发送\n        payload = videoMessageContent.encode();\n        resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null);\n        checkSendMessageResult(resultSendMessage);\n\n        //测试发送位置消息\n        LocationMessageContent locationMessageContent = new LocationMessageContent();\n        //base64edData为位置图片的缩略图。缩略图的生成规则是，把图片压缩到120X120大小的方框内，45%的质量压缩为JPG格式，再把二进制做base64编码得到字符串。\n        thumbnailBase64edData = \"/9j/4AAQSkZJRgABAQAASABIAAD/4QCMRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAALSgAwAEAAAAAQAAAHgAAAAA/8AAEQgAeAC0AwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/bAEMAAwMDAwMDBQMDBQcFBQUHCQcHBwcJDAkJCQkJDA4MDAwMDAwODg4ODg4ODhERERERERQUFBQUFhYWFhYWFhYWFv/bAEMBAwQEBgUGCgUFChcQDRAXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXFxcXF//dAAQADP/aAAwDAQACEQMRAD8A/SGR0ZcRx7TkEHI7HPrUE5keJgeeD3qzG8boryksSAc7sD8BkcUxxB5MpJGcHbls9vrXJc2sPI+Y71UHP9//AOtRtT+6v/ff/wBaozLIufnQ89SB/jWbrGtWukWBvrpTJtdFVIgC7u52qqjPUk9zj1pt8qu3oOKcmoxWp0EewcIeB0qWuGtvFGkXKSTXoeykjkEEkNwgMiPwcHZuGMMpyDjB61JP4k8OxNKn2gfufvko+B8wUYwpzknt25rLmi9eY1dOaduU7GX7h9cH+VVYpNvy4+9iufj1zQ50jWG4w865RSHGeGPoOcKeDzT08Q6KwtpEuNwupPLiwj/M64yPu8Yz3q4uNtyHTl2OmJaKxjDYVlJHB+lUo3SPLIxBY5YgKcn6kVkS+NfDqRPH9r+aJyrBUdiGIOOAp/utz0rShvDcwpcQszJIodG8scg8g8pmtE4S0uQ4Sjq0WYEywKOzAIVw2MA8Y6ev9Kesc1upclD0HQ9yB61JGZfKPmYA6klVHHrwO1VZTCRIAzsNg25Zsbuf/rUn2Qjzrxxrer6LexR2sz28P2ZpYmS1+0fabkMdsPPC8Y7gnOQeKh1K8uZr+4W4vJYLp7eNns13lEd4jIUBQk4wpOQu7dxXp4ikBKg4xwfmYf1qg+l6dPcNcSpEZA/3nwTkJt6n2JH0rldKV22ztVeKily6rr3PJ9K1hra3sBcanJ8szblw/wC96R4YSYbGT/DwDn6U5dRktdPeEardEK8cbShGLZQyM45yMcE8nJxzgc16auiaPCAsdtERCpEZUcJkHOMdzgZpr6No0nMkETZ5O7acnk5I7k7jk9TnmkqT7luvBu9vyM3R9Nv21R9We9eezuogywuXAjLYIwrZHA6HIPJzXQSxp5VyM7go4P4CliEcUIt4yiogCKOOABgDJOTSSFzaT4YYC+nX8c11QXKcU5czuVdGk8uKY4J75AyPvN1rQz5rE+SrE8k7RWdo/KOh6M+0/TL1pxJuY+SxUbQfm7/qa0lbmZktiUoQpRUAIxwv19KjliieRgfvE7fmQHGecjNWQVViHIJHFKWQ4AI96zuUUBsT5fN6f7P/ANel3J/z2/8AHf8A69Wvs5PKlcf7oo+zN6r/AN8iquu4WP/Q/SqGMAHdGq/Tmo5olyGTBYHOCQOxpCzu2yTK4GcqAc5+mfSlQM6GQsuQTjKjscCuS3U2uMZdhXBXo3I7dPrVPWdNstXsm0++3NFIUJCMVYEMCGVgcqwPQirY+fZsBJbJOTjqM+9NZW2namMMFOW75HtSkk7qQ4yad4mLZeF/D1jaCwjgE6PKbh3nJlkeU4Jdnbkk7QPTAxTIfCGhxXFzdurSLcLsdWLEY3BiOuCMjpjpxXQshjQu0ecf7X/1qQyGLMTR55z97/61EYxS5Yr8EVKcpS5pSd/VmH/wjuiiVZYYnEiqEB3sPlAx2PbtUX/CN6KI4YxaqscLGSNASFVmAyQM8Zxn6810SyYUusYHb73/ANaodqoFAUfdB6e1NQjfYbqS/mM5vDeh3Ns7T2yMZnMrk5+Z9oXnB6YJ46c1eigS3t4bVGxEihUUksVVRgZ6n86vIEe0Vii8KxAxnsvrmqt9Pa2NkL+5AWOFS7lRzgKScYxUc0VLkS1E+Zxu3oOjjk2kqPlkU4x3GOCfTNRMyFWDZwV7g1g2/iS3jSYaik1p5CK+xiHJR87SNueeCCOxFTS+JtFgk+zvM+XiaUZjJyigk4xtOflPHXIrezMzdaOFbjy/l+93x9aEMDM7CPOW4PA4wPUiufj8V+HbiKNzJIRKxQAh/vL14PNdIZEQbUUH5sZyD+fWpdwK7ySFXQLgEkrx6+4P9K0DDGMfe5PY1AksjPsPAwSMH0/ClLyEhEJG4989hmiwHNeJPEv/AAjjxK9u8qSQzyB/NSMZhCnb855J3dv1rmtd8eGxv7LRpLBjNfRRum6Zesg4ThSN2SR15xkCu71HRrLU4ydSUy+WkiptkdCA4w4OxlyCAODWJfaFo9xILu4tUeaJNiu2SQoUqB1xwDgenXrVqxLuUdM1W4S5EYt3Fubv7MZQyffzIAdp525yK6yIYQoDyUHP4r/jXNaZoumtPJqJhHnRyecG3P8A6wlxu27tuce1dIVkA/dnJ2/h2Pc+1E92C2JiZFlMTFW+YDLDPX8aeFkYbgqnPov/ANehx5imcSAsibhhf/r08SiNVVScc/w5/rWdyiLy5v7v6H/Gjy5v7v6H/Gn+cys2OckHOD6Cl+0Seh/L/wCvVXA//9H9J5VAnwuB8g/iK9z6EVCqgRsxA4ZuS/oT7Gr7okn38H/vr/Cq4t7eNSzheCTnB6dfSuVGoiLMqxsyg7R0XGeR+FR73KSfuyMPuJJUdCCe9XQFXgH/ANC/wpjwr5ZRGHzryfm7/hS5b6juVXulcAYGNwJ+Zeg59ajkkR2Levuv+NXJl2Qu8Mau6qSicjcQOBnHGTXNLqOvtaCRtKRZzCz+XvJw4chV7cFec5qoxtsJs2PMG3aPXPVf/iqmj8qQAMMEKB94c4HsadZebNZxS3cKwzOil4+TtbHIz7GrXlxA/dB4ByFPfmk1Jp2Gmr6kYwI4l4CsSrD6gf1qrKkMkL2l6hdDkbT0KkYx9CKvSRq0YUkqpJBG3GRx3JqI+SATvZQpxnJxnGe7EVxyhJSTvqbRcWmraGJaaBosEc6pCWjkChg7s5I54yxJwM8DNOu9I0K6/eSWyNIFKBiCDtI2kcHpgnjtWwgQu+243A88Y6KPoafsjPV2P4n+gq2qrWjBOC3RyaeHtERfKS2QKhyAC2Mk59fUA1rkAsSc9s44P3hWgba1Lbgx5Vc4JHOOe1PjtoEbzFYkkEc5NTGlP2nNJ6IHOPLZIqxsiPlVYkgjlgcUpuAjodp6k/Mw9DVlzGZACwBQ8gjHUU0RRy7ZY5MAAnpnIPHfNdtrnPcZ5iyHaQqK33iDkn26DrWfOU8qXeMny+OM85FaRtywAMo5BP3R2/D0FV7iJRayOkhA2lTuGeM/hjmmlYLmVpW7yZgMYYgHPX7z1tMYhFtR0Jxnk+2OKoaKkZWRQwYFh1U/3m/rx+Fahtrdju5BHTA/POTVTXvMUXoVWMZV2EgxtPBPOcYqQloyUD7cds5/pUrW0JUjJGRjP+Wp+Iv75/P/AOyqLFFVfN2gJLwBj8v+A0v7/wD56/p/9jVnbH/eP5//AGVGI/7x/P8A+yosFz//0v0iDtuClQM9SM5/rRukkhcsexAX19qiJ2HKhEyOM9cfmK80l8PeJJ/FYv4YmZWvIpUvzcMFjtV/1kIhDjJbkfdKnOc5rgqVHBK0bnZSpqbak7aHpH9raarOWvYdkZAc+YnysTgBueCSDxST61piMqLdQ/NH5hIkThRzu69MHOeK8Q1CwgEOoJLY3CiS/iBO8YMmZHz/AKs52hhnr29KtCSzS/umTT5B5Nmzq5mB3/uUJUDyyemQMdTzjHFY+3fVHY8Muj/I9ohvrW4RJIJ/MWQkIUIYEr1AwTnHeokv7ectLZzLMEXDFTnB64O3OK8r0+4CxaU50t5MmUxtlf3e12EpI8vnKqc56Z4wea6DwPJa/Y7/AMmy+zMzq7gvk/OCRgFUwF6DGe/fNXGrzNIxqYflTl2/zPQDI6NhiTjrtBP5Upmlkj8xVcKox2/h4PGR6UFolY5UuPYY/ma4hb3Wv7XeFTOENwytCY/3AtiPvCTGN/Q/ezk4xXV6HDc7diGhKShs53cgHI6evvUI2gYXIH4D/wBmrj7bU/FxN0rWSb4yoiBRwGUglzkbgSMD8Tjqat22o+KpNRnha0Jt1jZoiY9hZwAQNz4GCc9QDWboRbbkXGo1ojrLdSZDk/LtYHv2PvTnht9wbIBJ4BUYz+dclqd540XRrubTLZY71IwYQ+05JiJYgAnJD9B6eteS/DTXPHB16+Pi6K5i05idiX3zuk68FVkYKcHJJyNvQDmsHUVKUaSi3e/oexh8ulicNVxntEuS2jeru7aLqfRDQIxyAg+mB/PFMlby2SIHam0kkc859vaooissYljQFeoICf40sCu0xQZCggkEDngfX+ddd0eJYVltjj595JwAMZ/XFIiSRShowUz8obA7kD6dKn8ozFtqqAG28g56CkBkgDKcYUKRjpySOlK7HYk3SspImyF4IAz+lZ1ww8iZjxlCDhSMkkdePbvUkxiLEna5yCeDuHHuMfrUDOFs5kCtjZ1xxyapNvcCvo4zBMPUgf8AjzVoi2VdwkZgFbaCSee471m6MT5cqhWPIPHszVoyyS5LSRlVJ9R/WnJ+8yVsKYtsZKMRz1bv/OmqjNhckn2I/wDiaebslxHBjByScE/oKVp59p2spbBwAvP86i7ZRAY5QAPmzgZ4HXv2pNk3q35D/CrNvHLLEH8x+fc/41P9nl/56P8Amf8AGq+YH//T/SaKQZJbrgdPQf8A66ebuAHac5J2j5TyarebL321AihwG8xVKvuwSOCDXM0upqmW3lhkZPmIwxONp/wqy0ieWHHQrkZ79azwoDFtwdQTgjHX8KmdmWKFCoOUHcjpn29qElYL6k9sSY8EYwSB7D0qSWISIy4GSCMmqKyPs8tlVh179STTJP8AVtiNQcHkE1FmVctuLgZYttA5/hwPzFVWdA4d3JJHUYOCPbjtT3TKNiMAgZ4J/rQ7+ZJkK2WPqPTPr7VaJsNwJB8hGMdX4zyPTPpUezkjarY4yMkfyp4ZVXYRyWJDZFOiXcwj4H3iW4PcYHt1ouFijPeQWCTXdyyQQW0Mks0jZ/dxqpLNjHIwK8a8P+J/CnxE1a7j0ua4862U3ZhnXZvgdgN6bS3TI3A4IzXsd9p8N4t1ZXUYnt7iFoJo243xurBlyOnHftXmfg74aeEvh9JfahoYufMuYykk946ERQAh2VNiqMHaMsecCvdwqwP1Wq8Q37TTltt8zycQ8X9Ypqglyfavv8j1SzUxQLDGQI1GMEnOPxFSExySNHtJIdRnjoQv41ylh4w0bULW5ksjIWtYfP2TIYTJGeFdPMwGUnjP6cjMMXibffWsUdsWF2FdmWQfuyDjB2hvT1B5AxnivnvawavGR7joVE7NWO4lEK+YixgEA8g45x1p0yW4jYD72PU9ua8+u/G32SwN/daXICJTGyGYk7Rn5yQPTqD0JGeoqxc+Lo0+3rHZ7hZIGJEuc7m2gYCMc+3NT7WHcv6vU7HaTPaWz7XYoTzyzc9qrXskb2LSRMSrHbnJx/niuKuvEyX+rQWRtyhljDK4fK4ZS/GVUnpg11DH/iTr/v4/U1zUq8pVXTa0OFucajpzVla6JdFYBJFbozYP4Fz/AErYcWwBwQxH8Oea5vRrq2cyRxyJIyuQyqwJHMgOcdPxrdlTbGZETkDcDuHUc9K9KbtJmkdh5YjaUUqVzg9evXingsku92dx/EoHByO3PFMX7SW5OPzxU6icfeOal6Mdhn2WLt8o7AquQPzo+zRf3l/75X/GobqGWR1IJHy47epqt9ll9T+lLm8gsf/U+5V1+5l1gBbqH7H5BdkBiWThC25QWYgdDyxwOtU5vEHiD/iXjTriMqXK3Cu0JZm8wKwG3PABI45yRW7F4F0aa4a4lmuJiqGA73U5QxeWckKCTgnJ7nrSweFrG3eF4muM28pkTDJjcG+X+HouMAdhx6V5dpy0Z6vPSVml+BiX3iDV5ra6ksby185Z1WMDZwh3AI+XbDjBZh2Hc843tPl8TnVj/aCpJpxt0MLqUALlRkjaS3JDnnjBFVF8F6V5MiB5lEjBXGV+YKG+98vJO85PXgV2m0rDDGSX2xcM3UkcZP1zWkIS3kzOpONrQX4BApd/mJX5ONpI6E9amlhHlONz/dP8R9PrVYPJHtZAvIIOc/3h/jUqtJPCzucLg8KMZ49ck4/Kre5yo4DxuNfSW1ew/tCW0MMmVsGCyfaePK8w4J8v8CufvdqyL67uLa/sf7ZZjfiyC3CADywxhkZ8HzEBJweAuB154r1QxxiNQikEAdM1DNY6fPIjzQJIckEuu7Pyn1z6Vg6Lu5X3OyNdKKi1seOaTq2m2mm2kdtC7hbp5P3sKuQyiNcZEgADbxt7lhjr1dDbafaLqtwXuHjldEnVMB/nkdiVZWHTnPXA4Iz09mj0/TymwW0IUNu2iNcZPU4x14pX0+xUNi3iG45bCKM855wPWpVJ7Mt4latL+rnmcGmWGseI5ImklSWezKFwQV+aIBmxubkqwABbPU8gcdnpOk2+n6INAmY3cbK6OzqUDCXO4cZwDk4reit7QXAmSBFl67wqhueOuM9OKhnYrIV27gyqTk46nHp7VvGmrXe+pzTrOVkttDhdN+H9joMV0NLuJku5oVhimkYP5UKNkRJtCEKemeT6GrtpoOsR6hZ3T6m/k2ykTKSQsjdQMHORzyScnA/Dqg6ryyEjjOD+XJ+tA+ZztXGSSB17D/69TGjGC5Yqw5Yicm3J3OLi0PXJXeSbUVUSIu3EjHb8i7hsJAO5wTkYIycVUk8O+IEu7SX+0hIkEQ8z946lpASw6Zz1AyTz1NejqgKhvMxUfkxFXO1Rlz1FN013Gq0vIadPWWOM3QDyqgVmHGTjk8epqK9t44NPZEGAGUj2O4U+SNVOMKeM9KZdKPskqRj+JDgD2HpVqmlJStqclo3cranj/wAO4oIPFmvKdLuLWQknzpJQySgysPlURIByc/ebgjr29icB0KqvJGBlv/rV5R4AvdOufEviKGzvri5dHBeKREWKIiVx8jIx39QASBwOO9ewLGXhXbgEE1vLe4I8p8a+Pta8Pa4NNtIo0VIopI43Qu940jkNHEwddpUD0bn8AesvvEz2d5eWi24ZraLemZAC7YUlAMHnnt6c9RXUCIfaleUBmC5UkZxj09OtXa4FTlGUnzaM7XUpyjFcu3nucGPGNwLaCWW0jRpY95VpGyPmYdk74zzzzSf8JnL/AM+0X/f1/wD43XZvcCNtm3djvTPtY/55it+WRnzR7H//1f0oigli3BWXDNu+6ep/GqqqduTgkkn7p7k/7VXUScqCzkHuCo4PcfhTBDcIAiScDpkDP8q4lvqdBVVSpwOhJOMYHP4mpmVHgifaGOwDOM8c1Myy7QHIPPWmBiIIQoYfKMlOvU9c1qnoQ9xhW2PWL9KVVt87Vj42kkd+o/xqDJZd5L53Eck9Bj0xTh5j/KozhQPwzU8vULkogEmWiYqAcYyRj9aiUhXVpHYgNjkkj7poR5I4mjJRM7vvdee/btTirjZ8uCSe/YDrn8aGtLATrLGv3WDfSpA3mj5e1VPOWJsueR2LCkNwjMWVgM9gy/40WQFm3yZ2BPAYAfTIqrNuklJRd67VXIOOhz2qzaAZ3bgSWyRkH+L2zUMituQ7COwxg9vqKpPQTRWIUOV38BxgM3PGOOtTgDzkUPjgZ2kH+99aVUkdWU527mypIGOen5e9SeSwkCAIQ6nIPTqPSpb0GhrQlMqgds45OP6CkPTkEje3SmqkzqGESkH/AGmP9ajljdFB8sD5gf4hn9aE3oBIVy2drgdqZdEi2lZSR8yg4OOgGajZnALeWnAzzk9PrT7ySIwvEjLgAEBSPr2qtboNLHlvgO8ubvxBrkdxewXBgCJ5UQcPGRLLw+5F+nBIyPxPrXPkLjPU9CR/KvJ/h9pmqQa7rFxqOmQ28Mh/dSJgPKRK5y2Hc8A+wzXr2XUKqjYOgyN3J/EU5vWwkVo1ZJlZtx+U9STxketXPNHpVWVpUm+8CcBeBjrk9z7UbrgfNsz342n+RrO1x3HvbGRt+cZ7U37Gf7wqi7tNIzkHqAPyHvSbD6foKq0guf/W+/dN8Sx61ZpqenXAlglZwrlAuSjFG4dAeGUjpV4anc5x5iE+m2P/AAFeX/Db/kR7D/rref8ApVLXYr/r61SRNzpP7SvO4Q/8AH9DUV1rDwWzzyrsihjLPsU/dQFiQASenaokqhq//IH1D/r1n/8ARRpOKGmzKt/HWjOtlIsk0bag5jhidJFkLbwhLLg7QCRnPqK1NC8Z6f4i+0S6U7ubZ1ilEimMqxG4DDIOx614i3/Id8M/9fE3/pRBW78Kfv8AiL/r9i/9FCo9nEttnoOv/ENNG1BdJSymupWiDsIwDjOF9upIxVXTPiYl7fW2mXOl3Ns11xE8owp2gZ/9CHcd+4IrkNf/AOR8/wC3aH/0ZHST/wDIe8O/WT+lfPzxE1WcU9D9Xw+R4OeXqvKHvcl73e9rntS3ygsWizuOf0x6077dAesP+fyqgOgpK9zkR+UXZqw39ssi4jKZYZPPTP0qFLuIOXldyckADgAduDVE/eX8P51DL/rG/CjlVhKTNk3dixyxOf8AaCn+dN8/Sc4LKD+Fc9L96qEn+srJotHeC3t9qlGUbgG6jv04JHao7iB4YHnKuViUuWUnOFGenIqt2i/3I/5Vv3n/ACCbr/rhJ/6BW0YptXIcnqea3/i4WEcQuLW48yd/LMeV3AYQ7sNgkYcdB1/Ona3rF0llfQWcKx3KTQQpJP5gRjNIq5I2pnarA8E5zXN+M/8AkP2H+f4beuh8W/cl/wCv6x/9Ct6+ojgqPNB8vX9TwKmLq2lr/VmVfBeo3Wp3N35kttdwiKKWCW2V1yJJJVbIYnoyHFehY/eIUVgRk4J64xXj3wT/AOPD/txg/wDSm6r2j/lvH9G/pXlZzRjSxUoU1Zafkd+W1JVMPGcnr/wSs7MzvvUYJHUnsBx0P1qLyo2OAq8+h/8AsRU8vf8A3/8A2QVFF94V46PUGQyxbMvCTk5ByOnapfNtv+eB/MVVj/1Uf+6KdRyom5//2Q==\";\n        locationMessageContent.setThumbnailByte(Base64.getDecoder().decode(thumbnailBase64edData));\n        locationMessageContent.setTitle(\"中国北京市海淀区阜成路北二街131号\");\n        //设置经纬度\n        locationMessageContent.setLatitude(39.926537312885166);\n        locationMessageContent.setLongitude(116.32154022158235);\n        //消息转成Payload并发送\n        payload = locationMessageContent.encode();\n        resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null);\n        checkSendMessageResult(resultSendMessage);\n\n        //测试发送文件消息\n        FileMessageContent fileMessageContent = new FileMessageContent();\n        //设置文件名\n        fileMessageContent.setName(\"野火产品简介.pptx\");\n        //设置文件大小\n        fileMessageContent.setSize(38394);\n        //设置文件链接\n        fileMessageContent.setRemoteMediaUrl(\"https://media.wfcoss.cn/firechat/file_message_sample.pptx\");\n        //消息转成Payload并发送\n        payload = fileMessageContent.encode();\n        resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null);\n        checkSendMessageResult(resultSendMessage);\n\n        //测试动态表情消息\n        StickerMessageContent stickerMessageContent = new StickerMessageContent();\n        stickerMessageContent.setWidth(753);\n        stickerMessageContent.setHeight(960);\n        stickerMessageContent.setRemoteMediaUrl(\"https://media.wfcoss.cn/firechat/sticker_message_sample.jpg\");\n        //消息转成Payload并发送\n        payload = stickerMessageContent.encode();\n        resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null);\n        checkSendMessageResult(resultSendMessage);\n\n        //测试链接消息\n        LinkMessageContent linkMessageContent = new LinkMessageContent();\n        linkMessageContent.setTitle(\"野火IM开发手册\");\n        linkMessageContent.setUrl(\"https://docs.wildfirechat.cn\");\n        linkMessageContent.setThumbnailUrl(\"https://docs.wildfirechat.cn/favicon.ico\");\n        linkMessageContent.setContentDigest(\"野火IM开发手册，关于野火的所有知识都在这里！\");\n        //消息转成Payload并发送\n        payload = linkMessageContent.encode();\n        resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null);\n        checkSendMessageResult(resultSendMessage);\n\n        //测试名片消息\n        CardMessageContent cardMessageContent = new CardMessageContent();\n        //类型：0，用户；1，群组；2，聊天室；3，频道\n        cardMessageContent.setType(0);\n        cardMessageContent.setTarget(\"FireRobot\");\n        cardMessageContent.setName(\"FireRobot\");\n        cardMessageContent.setPortrait(\"https://cdn2.wildfirechat.net/robot.png\");\n        cardMessageContent.setDisplayName(\"小火\");\n        cardMessageContent.setFrom(sender);\n        //消息转成Payload并发送\n        payload = cardMessageContent.encode();\n        resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null);\n        checkSendMessageResult(resultSendMessage);\n\n        //测试提醒消息\n        TipNotificationMessageContent tipNotificationMessageContent = new TipNotificationMessageContent();\n        tipNotificationMessageContent.setTip(\"这是一个提醒小灰条消息\");\n        //消息转成Payload并发送\n        payload = tipNotificationMessageContent.encode();\n        resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null);\n        checkSendMessageResult(resultSendMessage);\n\n        //测试富通知消息\n        RichNotificationMessageContent richNotificationMessageContent = new RichNotificationMessageContent(\"产品审核通知\", \"您好，您的SSL证书以审核通过并成功办理，请关注\", \"https://www.wildfirechat.cn\")\n            .remark(\"谢谢惠顾\")\n            .exName(\"证书小助手\")\n            .appId(\"1234567890\")\n            .addItem(\"登陆账户\", \"野火IM\", \"#173177\")\n            .addItem(\"产品名称\", \"域名wildifrechat.cn申请的免费SSL证书\", \"#173177\")\n            .addItem(\"审核通过\", \"通过\", \"#173177\")\n            .addItem(\"说明\", \"请登陆账户查看处理\", \"#173177\");\n        //消息转成Payload并发送\n        payload = richNotificationMessageContent.encode();\n        resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null);\n        checkSendMessageResult(resultSendMessage);\n\n        //测试流式文本消息\n        testStreamingText(sender, conversation);\n    }\n\n    //消息相关表分为2类，分表是:t_messages_x和t_user_messages_y，并且是分表存储的。表内存储数据和分表规则请参考 https://docs.wildfirechat.cn/faq/server.html 问题2\n    /**\n     * 消息分表计算测试\n     * <p>\n     * 演示如何计算消息存储的分表名称：\n     * <ul>\n     * <li>用户消息表：t_user_messages_x (x为用户ID哈希值%128)</li>\n     * <li>消息表：t_messages_y (y为年份*12+月份)</li>\n     * </ul>\n     * </p>\n     */\n    static void testMessageSharding() {\n        String userId = \"user1\";\n        // 计算用户消息表：使用用户ID的哈希值对128取模\n        int hashId = Math.abs(userId.hashCode())%128;\n        String userMessageTable = \"t_user_messages_\" + hashId;\n        System.out.println(\"user:\" + userId + \" user messages table is \" + userMessageTable);\n\n        // 计算消息表：使用年份和月份\n        Calendar calendar = Calendar.getInstance();\n        Date date = new Date();\n        calendar.setTime(date);\n        int month = calendar.get(Calendar.MONTH);\n        int year = calendar.get(Calendar.YEAR);\n        year %= 3;\n        String messageTable = \"t_messages_\" + (year * 12 + month);\n        System.out.println(\"This month save message to table \" + messageTable);\n    }\n\n    /**\n     * 从数据库读取消息内容测试\n     * <p>\n     * 演示如何从数据库的二进制数据解析消息内容：\n     * <ul>\n     * <li>从数据库读取_messageContent字段</li>\n     * <li>解析为协议栈MessageContent对象</li>\n     * <li>使用MessageContentFactory解码为具体消息类型</li>\n     * <li>处理不同类型的消息（文本、图片、语音等）</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当解析过程中发生错误时抛出异常\n     */\n    static void testReadMessageContentFromDB() throws Exception {\n        //从数据库t_messages_x表中读取到消息内容字段_data的二进制数据为\n        byte[] data = {8,1,18,5,72,101,108,108,111,64,3};\n        //1. 先把二进制数据转化为协议栈消息内容。\n        WFCMessage.MessageContent protoContent = WFCMessage.MessageContent.parseFrom(data);\n        //2. 调用MessageContentFactory接口解析为消息内容。\n        MessageContent messageContent = MessageContentFactory.decodeMessageContent(protoContent);\n        //3. 检查是哪种消息，如果没有定义，会回落到UnknownMessageContent。自定义消息看本函数最后的注释。\n        if(messageContent instanceof TextMessageContent) {\n            TextMessageContent txt = (TextMessageContent)messageContent;\n            System.out.println(\"读取到的是文本消息，内容为：\" + txt.getText());\n        } else if(messageContent instanceof ImageMessageContent) {\n            ImageMessageContent img = (ImageMessageContent) messageContent;\n            System.out.println(\"读取到的是图片消息，图片链接为：\" + img.getRemoteMediaUrl());\n        } else if(messageContent instanceof SoundMessageContent) {\n            SoundMessageContent sound = (SoundMessageContent) messageContent;\n            System.out.println(\"读取到的是声音消息，声音链接为：\" + sound.getRemoteMediaUrl());\n        }\n\n        byte[] data2 = {8,3,18,8,91,-27,-101,-66,-25,-119,-121,93,42,-106,33,-1,-40,-1,-32,0,16,74,70,73,70,0,1,1,0,0,72,0,72,0,0,-1,-31,0,-128,69,120,105,102,0,0,77,77,0,42,0,0,0,8,0,5,1,18,0,3,0,0,0,1,0,1,0,0,1,26,0,5,0,0,0,1,0,0,0,74,1,27,0,5,0,0,0,1,0,0,0,82,1,40,0,3,0,0,0,1,0,2,0,0,-121,105,0,4,0,0,0,1,0,0,0,90,0,0,0,0,0,0,0,72,0,0,0,1,0,0,0,72,0,0,0,1,0,2,-96,2,0,4,0,0,0,1,0,0,0,120,-96,3,0,4,0,0,0,1,0,0,0,90,0,0,0,0,-1,-19,0,56,80,104,111,116,111,115,104,111,112,32,51,46,48,0,56,66,73,77,4,4,0,0,0,0,0,0,56,66,73,77,4,37,0,0,0,0,0,16,-44,29,-116,-39,-113,0,-78,4,-23,-128,9,-104,-20,-8,66,126,-1,-64,0,17,8,0,90,0,120,3,1,34,0,2,17,1,3,17,1,-1,-60,0,31,0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,-1,-60,0,-75,16,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,125,1,2,3,0,4,17,5,18,33,49,65,6,19,81,97,7,34,113,20,50,-127,-111,-95,8,35,66,-79,-63,21,82,-47,-16,36,51,98,114,-126,9,10,22,23,24,25,26,37,38,39,40,41,42,52,53,54,55,56,57,58,67,68,69,70,71,72,73,74,83,84,85,86,87,88,89,90,99,100,101,102,103,104,105,106,115,116,117,118,119,120,121,122,-125,-124,-123,-122,-121,-120,-119,-118,-110,-109,-108,-107,-106,-105,-104,-103,-102,-94,-93,-92,-91,-90,-89,-88,-87,-86,-78,-77,-76,-75,-74,-73,-72,-71,-70,-62,-61,-60,-59,-58,-57,-56,-55,-54,-46,-45,-44,-43,-42,-41,-40,-39,-38,-31,-30,-29,-28,-27,-26,-25,-24,-23,-22,-15,-14,-13,-12,-11,-10,-9,-8,-7,-6,-1,-60,0,31,1,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,-1,-60,0,-75,17,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,119,0,1,2,3,17,4,5,33,49,6,18,65,81,7,97,113,19,34,50,-127,8,20,66,-111,-95,-79,-63,9,35,51,82,-16,21,98,114,-47,10,22,36,52,-31,37,-15,23,24,25,26,38,39,40,41,42,53,54,55,56,57,58,67,68,69,70,71,72,73,74,83,84,85,86,87,88,89,90,99,100,101,102,103,104,105,106,115,116,117,118,119,120,121,122,-126,-125,-124,-123,-122,-121,-120,-119,-118,-110,-109,-108,-107,-106,-105,-104,-103,-102,-94,-93,-92,-91,-90,-89,-88,-87,-86,-78,-77,-76,-75,-74,-73,-72,-71,-70,-62,-61,-60,-59,-58,-57,-56,-55,-54,-46,-45,-44,-43,-42,-41,-40,-39,-38,-30,-29,-28,-27,-26,-25,-24,-23,-22,-14,-13,-12,-11,-10,-9,-8,-7,-6,-1,-37,0,67,0,7,7,7,7,7,7,12,7,7,12,17,12,12,12,17,23,17,17,17,17,23,30,23,23,23,23,23,30,36,30,30,30,30,30,30,36,36,36,36,36,36,36,36,43,43,43,43,43,43,50,50,50,50,50,56,56,56,56,56,56,56,56,56,56,-1,-37,0,67,1,9,9,9,14,13,14,25,13,13,25,59,40,33,40,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,-1,-35,0,4,0,8,-1,-38,0,12,3,1,0,2,17,3,17,0,63,0,-10,-105,36,113,72,-120,-60,-28,-43,67,116,17,-128,110,51,84,39,-15,5,-67,-76,-51,4,-118,119,41,80,49,-126,14,-29,-113,-49,-38,-67,7,-95,-58,107,94,95,-38,105,-42,-19,61,-53,-31,87,0,-128,50,121,-10,21,-25,45,-29,24,83,82,-70,-108,40,72,-99,48,27,119,-33,-37,-128,15,-79,-58,113,92,55,-118,-4,69,117,37,-52,-78,70,75,64,73,-17,-110,51,-39,-79,-45,25,3,-81,21,-64,92,11,-15,8,126,112,79,126,120,-4,51,92,115,-100,-37,-9,122,29,52,-24,74,105,-72,-90,-19,-65,-111,-35,-66,-69,61,-68,-53,58,42,-74,27,40,115,-100,1,-33,7,-127,-57,-91,83,58,-91,-68,-118,-17,104,29,100,35,-126,15,0,-6,-12,-19,-19,92,4,-113,118,-15,-94,-88,99,-22,15,92,-109,-40,119,-85,80,-36,62,37,-106,33,-60,100,29,-93,-48,-25,56,29,-64,-17,-51,115,52,-57,99,-83,77,98,-2,11,127,32,-50,-78,4,108,-126,-92,-110,119,117,-4,61,106,57,-17,93,-26,73,-29,-111,67,63,-16,-89,0,-12,-55,36,86,108,50,92,-56,-56,-118,-83,16,94,51,-73,-8,122,-125,-109,-127,-118,-93,20,-47,-68,-98,77,-72,43,-55,63,54,122,-46,72,71,71,113,114,-56,-65,56,42,-52,119,21,-58,1,-4,77,85,121,-30,114,55,124,-121,24,76,-13,-100,-5,-42,125,-36,-26,84,38,104,-39,-101,3,110,50,112,123,-3,69,101,-61,-26,93,72,-85,24,36,-81,60,123,125,105,-88,-36,-92,-101,-47,29,11,106,119,118,-73,94,76,39,115,47,-54,-85,-100,-125,-63,-12,-21,89,-15,60,-87,116,34,-108,5,12,-92,-85,12,17,-45,-7,118,53,89,-95,-119,51,113,43,48,-105,35,29,0,30,-60,99,53,-87,110,-10,-122,53,86,-61,73,-27,-107,100,28,6,-7,-117,103,-111,-12,-4,-86,-29,22,-12,71,68,48,-107,102,-38,81,45,44,75,4,108,-77,51,0,112,-7,92,-98,61,57,-29,62,-11,12,119,112,-63,112,-86,-79,-110,-96,-113,-108,31,76,-9,-21,89,119,87,119,22,-13,-20,0,5,-112,100,41,-29,0,-3,106,-60,55,114,-35,-121,72,16,-123,3,-25,96,6,6,61,-22,26,125,76,26,107,70,109,127,104,91,121,-93,-51,82,-117,-53,15,44,101,-78,121,-28,-6,-9,-87,63,-75,108,-1,0,-65,117,-7,-113,-2,38,-78,5,-12,-117,43,66,2,-56,-82,49,-114,-52,13,46,-47,-1,0,62,107,-2,127,26,66,63,-1,-48,-56,95,22,107,-47,76,100,-98,77,-15,18,119,70,-40,110,15,108,-29,-75,96,-99,73,-98,-19,-81,-28,33,-92,57,-7,-113,31,120,99,-74,51,-114,-43,-115,-2,-115,55,49,57,-114,83,-50,1,57,31,90,-123,-32,-77,-126,48,-9,-82,-46,-69,119,28,126,-107,-33,38,-102,62,-49,-22,-72,123,93,-46,-115,-97,94,-97,-25,-8,124,-55,-18,-60,74,-54,-81,-72,-122,31,46,14,20,-100,114,115,75,106,-126,62,-124,-111,-35,123,84,105,61,-100,80,18,-71,117,99,-64,39,63,-50,-102,99,-45,20,3,-27,21,99,-3,-46,113,-4,-21,37,8,-89,116,-48,-29,70,-115,39,120,114,-81,-101,-4,-6,-36,-110,107,56,102,64,-69,8,92,-16,65,-30,-95,58,109,-76,24,49,35,-79,-11,-49,122,122,36,24,-38,37,32,30,10,-25,-113,-64,-29,53,105,4,44,-83,22,91,110,49,77,66,45,90,-58,-79,-62,81,113,-65,-77,95,-121,-11,-9,-107,-30,104,-115,-69,70,11,68,-93,42,64,60,-29,61,50,122,85,120,-51,-91,-118,-77,8,-104,-18,60,100,-126,71,29,51,82,-91,-79,15,-78,89,126,78,78,11,-127,-102,-122,-14,-54,51,-123,15,-27,-10,1,-71,31,-104,-88,-27,-108,85,-30,-114,9,-48,-28,94,-46,-107,53,117,-67,-19,-7,108,53,-11,-105,-115,-119,94,-11,98,-33,83,-5,88,109,-31,35,10,57,36,-11,-51,103,-86,-39,-37,-87,-118,100,-13,14,70,73,-28,115,-23,-116,98,-81,75,13,-100,104,-47,-85,70,-86,-36,-116,113,-45,-90,105,-62,83,-21,35,76,36,-15,11,87,53,-90,-24,-74,-46,51,-57,-70,-44,-119,7,117,-64,-21,-8,-43,41,55,-78,-106,96,-84,-60,-29,10,14,127,17,82,91,52,83,-88,107,121,76,110,123,117,6,-97,63,-37,35,6,70,35,-53,-58,95,-41,-118,-87,67,-98,23,102,-72,-72,70,-67,46,119,-73,-106,-65,-16,73,13,-78,69,-120,-26,64,-27,120,59,-80,74,-25,-73,53,98,11,117,-74,-120,-61,110,-82,67,28,-100,100,-32,-12,-19,89,63,104,18,66,22,70,-37,-98,-125,-1,0,-78,-22,104,2,-30,-43,-116,-112,74,118,-16,91,60,-12,-10,-87,-25,-117,-39,19,46,88,-59,78,52,-44,-83,-41,77,63,95,-21,-95,-90,-17,-28,-87,38,108,-20,24,37,78,118,-9,-23,85,-65,-76,-109,-2,126,-37,-2,-7,-84,-24,110,-110,-32,52,-77,-56,16,-55,-14,-99,-96,127,42,119,-39,-20,-1,0,-25,-69,127,-33,20,70,73,-22,-1,0,-81,-60,-62,21,121,-30,-91,-93,-11,-73,-7,-97,-1,-47,-13,86,-79,-75,40,35,-73,115,-26,-89,44,-64,-11,-49,-46,-85,125,-102,-44,41,75,-103,76,-104,28,110,-32,-127,-11,-17,90,87,58,78,-105,115,23,-103,-89,-7,-16,-52,-68,50,-19,56,31,82,79,-14,-84,-56,116,-55,96,50,111,38,87,59,72,35,-8,122,-11,-21,-57,76,-41,76,-30,-87,62,68,-109,126,90,-2,7,-46,42,-12,-88,105,24,94,-2,119,-4,2,59,61,-118,69,-71,-115,-29,63,-34,31,49,63,94,-108,-65,-39,42,-101,101,46,-15,-106,28,-90,3,17,-97,66,15,79,-62,-84,105,-106,-42,8,-81,45,-35,-39,-118,80,-60,-58,0,-56,-29,-66,49,-36,-43,-58,-110,24,80,92,92,124,-15,0,72,116,31,51,30,-36,103,-16,53,-83,58,92,-16,114,106,-1,0,61,-65,83,120,60,53,106,124,-50,59,108,-81,-2,90,-94,-100,86,-10,-63,68,23,50,9,7,77,-92,108,97,-114,-107,24,123,13,61,-116,46,-122,76,-1,0,19,124,-57,-114,-39,-88,90,43,77,78,63,38,22,-39,34,100,-128,-4,16,62,-67,106,-76,122,92,-40,-112,76,1,25,-2,30,77,39,25,69,39,21,-13,-36,-47,86,-108,-26,-91,70,23,125,-9,94,-102,-105,62,-47,-89,92,98,55,80,57,-21,-45,21,19,105,-79,92,-60,69,-84,-67,121,33,-85,5,1,12,-5,65,96,50,-96,30,13,89,-77,55,48,-36,-84,123,-68,-73,110,-57,-80,-12,53,-50,-86,115,59,77,28,75,25,10,-14,-28,-81,78,-9,-46,-21,66,91,88,-34,-58,115,37,-64,84,32,-29,97,-50,72,-1,0,103,21,110,105,-19,100,119,-14,-32,50,116,-49,35,2,-75,-38,-40,-54,86,89,73,125,-71,-57,-29,89,-14,91,91,-93,-19,102,-7,67,18,-96,13,-68,-97,82,43,89,-63,-63,90,59,29,-33,83,-83,66,42,-99,36,-100,111,-42,-41,-11,-41,79,45,-118,70,-22,101,-128,45,-88,109,-96,-13,-14,-12,-4,106,-11,-117,106,18,6,102,37,83,56,33,-121,62,-72,-59,18,78,-52,60,-72,48,-101,57,-32,-16,5,53,-11,6,-56,-114,80,-24,-39,36,49,-23,-116,86,119,-77,-67,-54,-70,-93,37,41,77,-39,105,110,-97,-103,45,-59,-67,-75,-55,-40,96,5,-67,65,34,-85,65,113,119,106,-37,38,-121,100,99,-115,-67,-66,-72,21,104,-33,9,35,-61,-71,-34,-68,115,-42,-103,34,77,119,15,-109,-26,109,61,65,61,127,-3,85,-77,-9,-75,-114,-26,-14,81,-109,-10,-108,-2,47,43,107,-22,85,-69,-75,-114,85,23,69,25,85,-79,-73,-113,-61,53,71,-20,-53,-22,-1,0,-112,-85,34,-62,-11,-94,42,-78,-126,-47,-127,-104,-40,-15,-41,-11,-51,71,-10,13,75,-2,121,67,-7,10,-58,81,-109,119,72,-15,-85,-13,-44,-105,55,-78,-4,63,-32,-97,-1,-46,-13,-53,13,114,91,35,-10,75,-112,39,44,8,83,-72,-81,-25,88,-41,87,-9,-46,-53,44,-79,-110,9,-24,0,-57,-89,95,-89,52,-21,84,70,-69,73,-92,108,-128,-69,-79,-22,71,99,91,58,60,58,57,-55,-65,108,-17,-18,50,64,39,-81,0,-13,90,71,17,86,114,80,115,-75,-114,-72,87,-85,87,-106,28,-10,-79,-54,-120,-18,25,21,-101,57,-112,-112,8,25,28,-46,-108,-69,-45,-89,81,38,25,-41,35,25,-56,-28,127,47,122,-24,-18,-82,-30,-114,86,-122,-55,93,81,71,67,-45,32,-111,-59,103,-119,-29,-110,-15,-89,-68,-52,-127,8,5,71,0,-127,-98,-3,115,-8,-12,-84,-107,-31,61,31,-52,-59,94,19,-75,-2,102,91,106,-73,18,-50,110,66,-82,126,-18,20,118,62,-99,-21,98,-40,94,-36,-18,-107,-113,-106,79,56,60,26,-102,-2,-17,69,8,-115,-90,64,-48,48,35,119,-89,35,-97,-54,-85,-51,127,111,18,-119,-93,109,-57,-17,21,35,-97,-91,118,104,-92,-36,-27,115,-33,-53,-86,40,-13,58,-75,46,-105,103,-8,-108,46,26,72,-100,-61,49,8,1,-49,-103,-125,-55,-49,-75,72,-94,21,121,24,-111,113,-69,44,115,-4,38,-85,106,23,-81,-88,58,-92,41,-76,49,-63,81,-17,-45,-82,105,-15,66,-74,50,57,40,74,-80,-37,-13,99,-116,-5,15,-25,92,-13,-102,82,-45,83,25,-30,23,-75,115,-118,-26,-118,-47,62,-33,-89,-34,105,-36,61,-36,-74,-94,104,-2,93,-128,96,47,79,95,-89,-46,-79,30,-26,43,-56,-4,-94,88,73,-41,13,-22,43,-96,-74,-79,-13,-95,-35,110,-50,114,15,76,-112,-92,122,-109,-57,79,122,-82,-42,-47,90,50,-54,-48,-99,-29,-85,41,-56,97,-33,53,80,-124,90,-9,118,71,-93,44,52,-36,82,-125,-76,118,125,127,-90,99,-37,90,52,110,90,92,50,-80,-57,-45,-89,53,-46,13,-77,-62,98,-72,-37,-18,59,-2,29,64,-88,38,-110,-55,-128,84,-119,-103,-92,81,-54,-16,70,115,-40,125,42,33,29,-62,46,75,29,-67,113,-36,123,-43,-62,-47,-42,46,-24,48,-40,106,112,114,-10,111,-103,63,63,-52,-75,45,-51,-78,71,-77,-55,84,35,0,62,54,-25,-14,-88,-25,-127,-25,24,19,-124,100,-25,110,57,31,-115,82,-44,101,96,-79,-62,-49,-69,-52,112,9,35,-97,-62,-90,77,66,-35,34,-14,-68,-123,5,65,37,-13,-116,-116,-16,8,-18,77,85,74,-9,-109,-26,-74,-33,-46,-45,-11,50,-83,-116,-123,42,-114,-116,-74,-5,-65,34,101,-14,102,-37,4,-63,-69,41,101,-5,-39,53,103,-5,34,-57,-42,-21,-4,-1,0,-64,-85,58,-53,80,-118,-9,-27,-72,42,-123,72,0,-14,63,30,57,-83,93,-106,-65,-13,-14,-65,-101,-1,0,-123,77,-29,100,-1,0,-81,-55,-99,48,-115,42,-47,85,18,78,-3,-9,-3,79,-1,-45,-15,-21,23,-14,100,71,-36,-119,-126,71,29,-120,31,-105,62,-107,110,-22,-32,75,127,24,104,-64,117,114,14,-47,-63,-19,-7,-109,-102,-94,44,90,24,93,-104,-126,78,-48,-84,15,66,79,97,-34,-81,70,-41,66,8,-40,-51,-13,-79,101,14,-40,35,35,-96,-84,93,86,-109,-115,-12,99,-10,-110,80,113,79,70,71,-10,-95,21,-56,75,-114,55,2,-64,-29,-98,-71,-29,21,64,-54,-55,51,-112,114,-69,-65,-50,125,-22,-12,-13,93,67,20,65,-45,18,109,-53,62,57,-25,-116,126,85,9,-116,-35,-92,81,-64,-87,-70,71,9,-41,28,-109,-116,-12,-51,17,73,46,102,111,75,11,42,-111,109,110,-107,-19,-35,25,-116,38,-72,-112,-57,110,55,22,60,34,-114,107,-82,-71,-16,70,-89,97,100,117,27,-87,-93,-40,-120,29,-45,56,32,99,-98,-36,-6,87,79,-92,-8,50,-21,68,-65,77,64,-70,92,-128,8,-107,49,-125,-125,-35,79,63,-113,78,43,91,-59,86,23,-6,-83,-113,-40,-20,84,54,79,-52,-96,-10,-19,-109,-11,-81,14,-74,108,-99,104,66,-116,-105,47,86,118,-45,-64,56,83,-108,-22,45,86,-56,-14,81,119,-89,40,-60,112,-116,-102,-71,29,-11,-99,-36,98,63,41,11,3,-55,-50,56,-19,89,-73,122,61,-34,-97,4,-46,93,20,-114,72,24,41,-119,-114,28,-18,-18,7,112,43,30,-37,-9,99,121,60,-26,-66,-122,21,-7,-67,-24,-67,11,-114,109,82,30,-20,-30,-83,-38,-42,61,75,79,-15,89,-48,109,36,-79,-103,68,-119,-68,-108,35,7,4,-16,65,62,-107,-50,-49,126,13,-52,-123,-119,116,-105,59,123,40,-17,-113,74,-29,-26,121,-122,86,99,-50,112,63,15,74,-69,110,-78,-76,-53,110,-89,40,-1,0,120,-111,-114,-39,-3,43,10,88,120,83,-85,42,-76,-107,-100,-65,18,99,-103,-44,117,-81,75,110,-58,-68,122,-108,86,-52,85,99,-55,-24,74,-100,-126,42,97,124,-84,-54,-14,-126,-86,-5,-79,-113,110,59,-43,86,-46,-115,-86,-105,36,-107,117,-56,61,56,-1,0,10,-84,109,36,86,88,-2,-8,-19,-20,43,-90,115,-108,86,-89,125,124,86,50,-124,20,-102,-47,110,-122,94,93,-61,52,-63,8,-7,66,113,-20,77,107,-24,26,109,-107,-19,-67,-44,-6,-119,-35,-28,4,-62,2,67,124,-57,-17,113,-44,83,36,-48,-96,-108,11,-105,114,56,-28,-116,96,-29,-80,-9,-86,109,103,21,-116,-122,-26,-38,86,60,96,-125,-116,-13,88,-42,-90,-22,65,-72,-53,-18,103,11,-61,86,109,-30,-86,37,37,-42,-51,127,90,29,-50,-97,-32,109,34,72,87,81,-73,-68,47,-126,89,21,-64,-64,-10,96,122,-30,-75,63,-31,31,79,-7,-17,103,-1,0,126,-105,-4,107,-125,-99,110,46,32,99,52,-60,22,24,-38,56,-49,29,112,6,49,88,-65,-39,103,-2,123,31,-54,-72,99,-105,-30,-27,119,26,-38,122,35,-70,88,110,95,-126,-110,107,-44,-1,-44,-13,123,93,71,-20,-110,125,-110,24,-64,-114,66,62,87,64,114,6,49,-57,122,126,-96,-70,44,-54,-92,126,-23,-103,-65,-128,-31,65,-9,29,-65,-6,-43,63,-120,-29,-115,52,107,9,81,64,118,39,44,7,39,-123,-22,105,-34,50,-73,-73,-126,59,111,34,53,78,71,-35,0,127,42,-13,37,27,-54,50,78,-41,27,-111,-124,-41,70,24,-102,-40,5,126,-5,-2,-9,-32,61,-115,86,-122,-2,11,55,41,105,0,87,-49,-51,51,13,-51,-97,108,-16,63,42,-91,-109,-104,-1,0,-33,74,77,87,-115,70,112,56,27,-21,-82,75,-38,123,-78,-40,-42,-82,42,-91,75,41,61,-74,59,-117,79,28,95,91,-22,17,-67,-42,-39,-94,-115,112,-22,-68,100,17,-41,-36,-42,-107,-25,-114,-27,18,-57,115,-89,64,-47,69,-56,38,65,-61,125,49,94,88,-3,71,-46,-67,34,-11,87,-2,17,104,78,58,36,88,-3,43,-56,-60,-32,-80,-48,-100,27,-122,-6,29,-104,108,77,89,66,109,-53,101,115,-104,-42,-11,100,-44,-27,121,-27,2,89,92,12,30,-104,-64,-82,84,-87,76,-79,-83,9,6,6,71,-67,67,-128,65,4,127,14,107,-39,-93,77,66,10,49,-40,-13,-28,-36,-101,-109,-22,85,-56,108,-79,25,60,115,67,-51,32,-112,75,25,-6,122,86,-107,-96,31,107,-76,-29,-84,-117,-4,-59,117,94,55,-73,-73,-123,109,-28,-118,53,70,114,119,21,0,19,-64,-21,85,123,73,33,-58,26,115,34,19,-90,106,113,-23,73,-88,-4,-78,-58,-47,9,8,28,-74,-42,28,-28,31,-18,-1,0,-11,-22,27,79,15,-33,93,-92,119,-119,44,113,36,-54,118,-87,39,62,-64,-6,103,-82,107,-48,108,-128,-14,44,-41,-79,-119,65,30,-59,106,-124,0,8,96,3,-96,65,-113,-5,-28,87,-105,87,48,-97,44,-107,-74,53,-85,-118,-100,-96,-95,39,116,114,-42,-102,6,-84,44,-38,-3,-14,-78,-82,-19,-80,115,-69,104,56,63,-113,-73,122,-24,-20,-76,27,75,-115,37,-115,-14,126,-7,73,12,-92,109,101,-29,-127,-17,93,58,-13,51,19,-49,-56,63,-12,26,117,-40,2,-22,5,28,3,-73,-118,-27,-87,-118,-99,69,-55,123,117,-45,-14,46,-98,42,80,-89,-54,-11,87,-40,-15,91,49,-88,36,98,97,19,-51,110,9,80,14,72,61,122,96,-25,-114,-68,85,-49,-75,63,-4,-8,55,-27,47,-1,0,21,94,-77,-128,-77,58,-81,0,71,-48,125,106,58,-19,88,-35,90,-27,58,104,-54,73,114,-33,99,-1,-39,48,1,58,90,104,116,116,112,58,47,47,49,57,50,46,49,54,56,46,49,46,56,49,58,56,48,47,102,115,47,49,47,50,48,50,53,47,48,50,47,49,56,47,48,55,47,51,55,47,52,48,47,77,51,108,110,99,87,49,51,99,122,74,114,45,49,45,49,55,51,57,56,51,53,52,54,48,45,116,66,98,71,82,110,49,90,119,56,111,79,46,106,112,103,64,3};\n        protoContent = WFCMessage.MessageContent.parseFrom(data2);\n        messageContent = MessageContentFactory.decodeMessageContent(protoContent);\n        if(messageContent instanceof TextMessageContent) {\n            TextMessageContent txt = (TextMessageContent)messageContent;\n            System.out.println(\"读取到的是文本消息，内容为：\" + txt.getText());\n        } else if(messageContent instanceof ImageMessageContent) {\n            ImageMessageContent img = (ImageMessageContent) messageContent;\n            System.out.println(\"读取到的是图片消息，图片链接为：\" + img.getRemoteMediaUrl());\n        } else if(messageContent instanceof SoundMessageContent) {\n            SoundMessageContent sound = (SoundMessageContent) messageContent;\n            System.out.println(\"读取到的是声音消息，声音链接为：\" + sound.getRemoteMediaUrl());\n        }\n\n        // 问题：MessageContentFactory是如何找到消息的？\n        // 答：MessageContentFactory在启动时会扫描自己的包cn.wildfirechat.sdk.messagecontent下的所有MessageContent子类，记住子类和消息类型的对应关系。\n        // 问题：自定义消息如何添加到MessageContentFactory中？\n        // 答：首先自定义消息需要继承MessageContent，然后有2个选择，1是放到此SDK的cn.wildfirechat.sdk.messagecontent包下打包SDK；2是调用MessageContentFactory中的registerCustomMessageContent方法手动关联。\n        // 比如 MessageContentFactory.registerCustomMessageContent(CustomTextMessageContent.class);\n    }\n\n    /**\n     * 检查消息发送结果\n     * <p>\n     * 验证消息是否发送成功，如果失败则退出程序。\n     * </p>\n     * @param resultSendMessage 消息发送结果\n     */\n    static void checkSendMessageResult(IMResult<SendMessageResult> resultSendMessage) {\n        if (resultSendMessage != null && resultSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"send message success\");\n        } else {\n            System.out.println(\"send message failure\");\n            System.exit(-1);\n        }\n    }\n\n    /**\n     * 流式文本消息测试\n     * <p>\n     * 演示如何发送流式文本消息，模拟AI逐字生成效果：\n     * <ul>\n     * <li>将长文本分段发送</li>\n     * <li>使用StreamTextGeneratingMessageContent表示正在生成</li>\n     * <li>使用StreamTextGeneratedMessageContent表示生成完成</li>\n     * </ul>\n     * </p>\n     * @param sender 发送者用户ID\n     * @param conversation 会话对象\n     * @throws Exception 当发送过程中发生错误时抛出异常\n     */\n    static void testStreamingText(String sender, Conversation conversation) throws Exception {\n        // 准备要发送的长文本\n        String fullText = \"北京野火无限网络科技有限公司是成立于2019年底的一家科技创新企业，公司的主要目标是为广大企业和单位提供优质可控、私有部署的即时通讯和实时音视频能力，为社会信息化水平提高作出自己的贡献。\\n\" +\n            \"\\n\" +\n            \"野火IM是公司研发一套自主可控的即时通讯组件，具有全部私有化、功能齐全、协议稳定可靠、全平台支持、安全性高和支持国产化等技术特点。客户端分层设计，既可开箱即用，也可与现有系统深度融合。具有完善的服务端API和自定义消息功能，可以任意扩展功能。代码开源率高，方便二次开发和使用。支持多人实时音视频和会议功能，线上沟通更通畅。\\n\" +\n            \"\\n\" +\n            \"公司致力于开源项目，在Github上开源项目广受好评，其中Server项目有超过7.1K个Star，组织合计Star超过1万个。有大量的技术公司受益于我们的开源，为自己的产品添加了即时通讯能力，这也算是我们公司为社会信息化建设做出的一点点贡献吧。\\n\" +\n            \"\\n\" +\n            \"公司以即时通讯技术为核心，持续努力优化和完善即时通讯和实时音视频产品，努力为客户提供最优质的即时通讯和实时音视频能力。\";\n        int i = 0;\n        String streamId = UUID.randomUUID().toString();\n        while (i < fullText.length()) {\n            i+= 15;\n\n            boolean finish = i >= fullText.length();\n            String partText = finish?fullText:fullText.substring(0, i);\n\n            MessageContent messageContent;\n            if(finish) {\n                messageContent = new StreamTextGeneratedMessageContent(partText, streamId);\n            } else {\n                messageContent = new StreamTextGeneratingMessageContent(partText, streamId);\n            }\n            //消息转成Payload并发送\n            MessagePayload payload = messageContent.encode();\n\n            IMResult<SendMessageResult> resultSendMessage = MessageAdmin.sendMessage(sender, conversation, payload, null);\n            if (resultSendMessage != null && resultSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"send message success\");\n            } else {\n                System.out.println(\"send message failure\");\n                System.exit(-1);\n            }\n\n            Thread.sleep(500);\n        }\n    }\n\n\n    //***********************************************\n    //****  测试频道功能\n    //***********************************************\n    /**\n     * 频道管理API测试\n     * <p>\n     * 测试以下功能：\n     * <ul>\n     * <li>创建频道</li>\n     * <li>获取频道信息</li>\n     * <li>关注频道</li>\n     * <li>取消关注频道</li>\n     * <li>检查用户关注状态</li>\n     * <li>销毁频道（标记为已删除状态）</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testChannelApi() throws Exception {\n        String channelName = \"MyChannel\";\n        String channelOwner = \"user1\";\n        InputCreateChannel inputCreateChannel = new InputCreateChannel();\n        inputCreateChannel.setName(channelName);\n        inputCreateChannel.setOwner(channelOwner);\n        IMResult<OutputCreateChannel> resultCreateChannel = ChannelAdmin.createChannel(inputCreateChannel);\n        if (resultCreateChannel != null && resultCreateChannel.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"success\");\n            inputCreateChannel.setTargetId(resultCreateChannel.result.getTargetId());\n        } else {\n            System.out.println(\"create channel failure\");\n            System.exit(-1);\n        }\n\n        IMResult<OutputGetChannelInfo> resultGetChannel = ChannelAdmin.getChannelInfo(inputCreateChannel.getTargetId());\n        if(resultGetChannel != null && resultGetChannel.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS\n            && resultGetChannel.getResult().getName().equals(channelName)\n            && resultGetChannel.getResult().getOwner().equals(channelOwner)) {\n            System.out.println(\"success\");\n        } else {\n            System.out.println(\"get channel failure\");\n            System.exit(-1);\n        }\n\n        String subscriber = \"aaa\";\n        IMResult<Void> voidIMResult = ChannelAdmin.subscribeChannel(inputCreateChannel.getTargetId(), subscriber);\n        if(voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"subscribeChannel success\");\n        } else {\n            System.out.println(\"subscriber channel failure\");\n            System.exit(-1);\n        }\n\n        Thread.sleep(100);\n        IMResult<OutputBooleanValue> booleanIMResult = ChannelAdmin.isUserSubscribedChannel(subscriber, inputCreateChannel.getTargetId());\n        if(booleanIMResult != null && booleanIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && booleanIMResult.getResult().value) {\n            System.out.println(\"subscribe status is correct\");\n        } else {\n            System.out.println(\"subscribe status is incorrect\");\n            System.exit(-1);\n        }\n\n\n        voidIMResult = ChannelAdmin.unsubscribeChannel(inputCreateChannel.getTargetId(), subscriber);\n        if(voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"unsubscribeChannel success\");\n        } else {\n            System.out.println(\"unsubscriber channel failure\");\n            System.exit(-1);\n        }\n        Thread.sleep(100);\n\n        booleanIMResult = ChannelAdmin.isUserSubscribedChannel(subscriber, inputCreateChannel.getTargetId());\n        if(booleanIMResult != null && booleanIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && !booleanIMResult.getResult().value) {\n            System.out.println(\"subscribe status is correct\");\n        } else {\n            System.out.println(\"subscribe status is incorrect\");\n            System.exit(-1);\n        }\n\n        voidIMResult = ChannelAdmin.destroyChannel(inputCreateChannel.getTargetId());\n        if(voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"success\");\n        } else {\n            System.out.println(\"destroy channel failure\");\n            System.exit(-1);\n        }\n\n        resultGetChannel = ChannelAdmin.getChannelInfo(inputCreateChannel.getTargetId());\n        if(resultGetChannel != null && resultGetChannel.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && (resultGetChannel.getResult().getState() & ProtoConstants.ChannelState.Channel_State_Mask_Deleted) > 0) {\n            System.out.println(\"success\");\n        } else {\n            System.out.println(\"get channel failure\");\n            System.exit(-1);\n        }\n    }\n\n    //***********************************************\n    //****  一些其它的功能，比如创建频道，更新用户设置等\n    //***********************************************\n    /**\n     * 通用API测试\n     * <p>\n     * 测试以下功能：\n     * <ul>\n     * <li>获取系统设置（如群组最大成员数）</li>\n     * <li>修改用户设置</li>\n     * <li>发送用户设置</li>\n     * <li>获取用户设置</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testGeneralApi() throws Exception {\n        IMResult<SystemSettingPojo> resultGetSystemSetting  =  GeneralAdmin.getSystemSetting(Group_Max_Member_Count);\n        if (resultGetSystemSetting != null && resultGetSystemSetting.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"success\");\n        } else {\n            System.out.println(\"get system setting failure\");\n            System.exit(-1);\n        }\n\n        IMResult<Void> resultSetSystemSetting = GeneralAdmin.setSystemSetting(Group_Max_Member_Count, \"2000\", \"最大群人数为2000\");\n        if (resultSetSystemSetting != null && resultSetSystemSetting.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"success\");\n        } else {\n            System.out.println(\"get system setting failure\");\n            System.exit(-1);\n        }\n\n        resultGetSystemSetting  =  GeneralAdmin.getSystemSetting(Group_Max_Member_Count);\n        if (resultGetSystemSetting != null && resultGetSystemSetting.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && resultGetSystemSetting.getResult().value.equals(\"2000\")) {\n            System.out.println(\"success\");\n        } else {\n            System.out.println(\"get system setting failure\");\n            System.exit(-1);\n        }\n\n        IMResult<HealthCheckResult> health = GeneralAdmin.healthCheck();\n        if(health != null && health.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(health.result);\n        } else {\n            System.out.println(\"health check failure\");\n            System.exit(-1);\n        }\n\n\n        //测试用户设置功能\n        IMResult<Void> setUserSettingResult = GeneralAdmin.setUserSetting(\"user1\", 1, \"test_key\", \"test_value\");\n        if (setUserSettingResult != null && setUserSettingResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"set user setting success\");\n        } else {\n            System.out.println(\"set user setting failure\");\n            System.exit(-1);\n        }\n\n        IMResult<UserSettingPojo> getUserSettingResult = GeneralAdmin.getUserSetting(\"user1\", 1, \"test_key\");\n        if (getUserSettingResult != null && getUserSettingResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && \"test_value\".equals(getUserSettingResult.getResult().getValue())) {\n            System.out.println(\"get user setting success\");\n        } else {\n            System.out.println(\"get user setting failure\");\n            System.exit(-1);\n        }\n\n        if (commercialServer) {\n            //测试会话置顶功能\n            IMResult<Void> setTopResult = GeneralAdmin.setConversationTop(\"user1\", ProtoConstants.ConversationType.ConversationType_Private, \"user2\", 0, true);\n            if (setTopResult != null && setTopResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"set conversation top success\");\n            } else {\n                System.out.println(\"set conversation top failure\");\n                System.exit(-1);\n            }\n\n            Thread.sleep(1000);\n            IMResult<Boolean> getTopResult = GeneralAdmin.getConversationTop(\"user1\", ProtoConstants.ConversationType.ConversationType_Private, \"user2\", 0);\n            if (getTopResult != null && getTopResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && getTopResult.getResult()) {\n                System.out.println(\"get conversation top success\");\n            } else {\n                System.out.println(\"get conversation top failure\");\n                System.exit(-1);\n            }\n\n            //取消置顶\n            setTopResult = GeneralAdmin.setConversationTop(\"user1\", ProtoConstants.ConversationType.ConversationType_Private, \"user2\", 0, false);\n            if (setTopResult != null && setTopResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"cancel conversation top success\");\n            } else {\n                System.out.println(\"cancel conversation top failure\");\n                System.exit(-1);\n            }\n\n            //测试获取会话文件\n            IMResult<FilesPojo> getConversationFilesResult = GeneralAdmin.getConversationFiles(ProtoConstants.ConversationType.ConversationType_Private, \"user2\", 0, \"user1\", 0, true, 10);\n            if (getConversationFilesResult != null && getConversationFilesResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"get conversation files success\");\n            } else {\n                System.out.println(\"get conversation files failure\");\n            }\n\n            //测试获取用户文件\n            IMResult<FilesPojo> getUserFilesResult = GeneralAdmin.getUserFiles(\"user1\", 0, true, 10);\n            if (getUserFilesResult != null && getUserFilesResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"get user files success\");\n            } else {\n                System.out.println(\"get user files failure\");\n            }\n\n            //测试获取单个文件信息\n            if (getUserFilesResult.getResult() != null && getUserFilesResult.getResult().files != null && !getUserFilesResult.getResult().files.isEmpty()) {\n                long messageId = getUserFilesResult.getResult().files.get(0).messageId;\n                IMResult<FilesPojo.FilePojo> getFileResult = GeneralAdmin.getFile(messageId);\n                if (getFileResult != null && getFileResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                    System.out.println(\"get file success\");\n                } else {\n                    System.out.println(\"get file failure\");\n                }\n            }\n        }\n    }\n\n    /**\n     * 聊天室管理API测试\n     * <p>\n     * 测试以下功能：\n     * <ul>\n     * <li>创建聊天室</li>\n     * <li>获取聊天室信息</li>\n     * <li>获取聊天室成员列表</li>\n     * <li>销毁聊天室</li>\n     * <li>获取用户的聊天室</li>\n     * <li>设置聊天室黑名单（仅商业版）</li>\n     * <li>获取聊天室黑名单（仅商业版）</li>\n     * <li>发送聊天室消息</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testChatroom() throws Exception {\n        String chatroomId = \"chatroomId1\";\n        String chatroomTitle = \"TESTCHATROM\";\n        String chatroomDesc = \"this is a test chatroom\";\n        String chatroomPortrait = \"http://pic.com/test123.png\";\n        String chatroomExtra = \"{\\'managers:[\\\"user1\\\",\\\"user2\\\"]}\";\n        IMResult<OutputCreateChatroom> chatroomIMResult = ChatroomAdmin.createChatroom(chatroomId,chatroomTitle, chatroomDesc, chatroomPortrait,chatroomExtra,ProtoConstants.ChatroomState.Chatroom_State_Normal);\n        if (chatroomIMResult != null && chatroomIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && chatroomIMResult.getResult().getChatroomId().equals(chatroomId)) {\n            System.out.println(\"create chatroom success\");\n        } else {\n            System.out.println(\"create chatroom failure\");\n            System.exit(-1);\n        }\n\n        IMResult<OutputGetChatroomInfo> getChatroomInfoIMResult = ChatroomAdmin.getChatroomInfo(chatroomId);\n        if (getChatroomInfoIMResult != null && getChatroomInfoIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (!getChatroomInfoIMResult.getResult().getChatroomId().equals(chatroomId)\n                || !getChatroomInfoIMResult.getResult().getTitle().equals(chatroomTitle)\n                || !getChatroomInfoIMResult.getResult().getDesc().equals(chatroomDesc)\n                || !getChatroomInfoIMResult.getResult().getPortrait().equals(chatroomPortrait)\n                || !getChatroomInfoIMResult.getResult().getExtra().equals(chatroomExtra)\n                || getChatroomInfoIMResult.getResult().getState() != ProtoConstants.ChatroomState.Chatroom_State_Normal) {\n                System.out.println(\"chatroom info incorrect\");\n                System.exit(-1);\n            } else {\n                System.out.println(\"chatroom info correct\");\n            }\n        } else {\n            System.out.println(\"get chatroom info failure\");\n            System.exit(-1);\n        }\n\n        IMResult<OutputStringList> memberList = ChatroomAdmin.getChatroomMembers(chatroomId);\n        if (memberList != null && memberList.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get chatroom member success\");\n        } else {\n            System.out.println(\"get chatroom member failure: \" + memberList.getErrorCode().msg);\n        }\n\n        IMResult<Void> voidIMResult = ChatroomAdmin.destroyChatroom(chatroomId);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"destroy chatroom done!\");\n        } else {\n            System.out.println(\"destroy chatroom failure\");\n            System.exit(-1);\n        }\n\n        Thread.sleep(1000);\n        getChatroomInfoIMResult = ChatroomAdmin.getChatroomInfo(chatroomId);\n        if (getChatroomInfoIMResult != null && getChatroomInfoIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && getChatroomInfoIMResult.getResult().getState() == ProtoConstants.ChatroomState.Chatroom_State_End) {\n            System.out.println(\"chatroom destroyed!\");\n        } else {\n            System.out.println(\"chatroom not destroyed!\");\n            System.exit(-1);\n        }\n\n        IMResult<OutputUserChatroom>  userChatroomIMResult = ChatroomAdmin.getUserChatroom(\"uygqmws2k\");\n        if(userChatroomIMResult != null && (userChatroomIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS || userChatroomIMResult.getErrorCode() == ErrorCode.ERROR_CODE_NOT_EXIST)) {\n            System.out.println(\"get user chatroom success\");\n        } else {\n            System.out.println(\"get user chatroom failure\");\n            System.exit(-1);\n        }\n\n        //测试设置聊天室全局禁言\n        IMResult<Void> setChatroomMuteResult = ChatroomAdmin.setChatroomMute(chatroomId, true);\n        if (setChatroomMuteResult != null && setChatroomMuteResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"set chatroom mute success\");\n        } else {\n            System.out.println(\"set chatroom mute failure\");\n            System.exit(-1);\n        }\n\n        //取消聊天室全局禁言\n        setChatroomMuteResult = ChatroomAdmin.setChatroomMute(chatroomId, false);\n        if (setChatroomMuteResult != null && setChatroomMuteResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"cancel chatroom mute success\");\n        } else {\n            System.out.println(\"cancel chatroom mute failure\");\n            System.exit(-1);\n        }\n\n        //下面仅专业版支持\n        if(commercialServer) {\n            //设置用户聊天室黑名单。0正常；1禁言；2禁止加入。\n            IMResult<Void> voidIMResult1 = ChatroomAdmin.setChatroomBlacklist(\"chatroom1\", \"oto9o9__\", 1);\n            if (voidIMResult1 != null && voidIMResult1.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"add chatroom black success\");\n            } else {\n                System.out.println(\"add chatroom black failure\");\n                System.exit(-1);\n            }\n\n            //获取聊天室黑名单\n            IMResult<OutputChatroomBlackInfos> blackInfos = ChatroomAdmin.getChatroomBlacklist(\"chatroom1\");\n            if (blackInfos != null && blackInfos.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && !blackInfos.getResult().infos.isEmpty()) {\n                boolean success = false;\n                for (OutputChatroomBlackInfos.OutputChatroomBlackInfo info : blackInfos.getResult().infos) {\n                    if (info.userId.equals(\"oto9o9__\")) {\n                        success = true;\n                        break;\n                    }\n                }\n                if (success) {\n                    System.out.println(\"add chatroom black success\");\n                } else {\n                    System.out.println(\"add chatroom black failure\");\n                    System.exit(-1);\n                }\n            } else {\n                System.out.println(\"add chatroom black failure\");\n                System.exit(-1);\n            }\n\n            //取消用户聊天室黑名单。0正常；1禁言；2禁止加入。\n            voidIMResult1 = ChatroomAdmin.setChatroomBlacklist(\"chatroom1\", \"oto9o9__\", 0);\n            if (voidIMResult1 != null && voidIMResult1.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"remove chatroom black success\");\n            } else {\n                System.out.println(\"remove chatroom black failure\");\n                System.exit(-1);\n            }\n\n            //获取聊天室黑名单\n            blackInfos = ChatroomAdmin.getChatroomBlacklist(\"chatroom1\");\n            if (blackInfos != null && blackInfos.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                boolean success = true;\n                for (OutputChatroomBlackInfos.OutputChatroomBlackInfo info : blackInfos.getResult().infos) {\n                    if (info.userId.equals(\"oto9o9__\")) {\n                        success = false;\n                        break;\n                    }\n                }\n                if (success) {\n                    System.out.println(\"remove chatroom black success\");\n                } else {\n                    System.out.println(\"remove chatroom black failure\");\n                    System.exit(-1);\n                }\n            } else {\n                System.out.println(\"remove chatroom black failure\");\n                System.exit(-1);\n            }\n\n            //设置聊天室管理员\n            IMResult<Void> voidIMResult2 = ChatroomAdmin.setChatroomManager(\"chatroom1\", \"UserId1\", 1);\n            if (voidIMResult2 != null && voidIMResult2.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"add chatroom manager success\");\n            } else {\n                System.out.println(\"add chatroom black failure\");\n                System.exit(-1);\n            }\n\n            //获取聊天室管理员\n            IMResult<OutputStringList> managers = ChatroomAdmin.getChatroomManagerList(\"chatroom1\");\n            if (managers != null && managers.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && !managers.getResult().getList().isEmpty() && managers.getResult().getList().contains(\"UserId1\")) {\n                System.out.println(\"add chatroom black success\");\n            } else {\n                System.out.println(\"add chatroom black failure\");\n                System.exit(-1);\n            }\n\n            //取消聊天室管理员\n            IMResult<Void> voidIMResult3 = ChatroomAdmin.setChatroomManager(\"chatroom1\", \"UserId1\", 0);\n            if (voidIMResult3 != null && voidIMResult3.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"add chatroom manager success\");\n            } else {\n                System.out.println(\"add chatroom black failure\");\n                System.exit(-1);\n            }\n\n            //获取聊天室管理员\n            IMResult<OutputStringList> managers2 = ChatroomAdmin.getChatroomManagerList(\"chatroom1\");\n            if (managers2 != null && managers2.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && !managers2.getResult().getList().contains(\"UserId1\")) {\n                System.out.println(\"add chatroom black success\");\n            } else {\n                System.out.println(\"add chatroom black failure\");\n                System.exit(-1);\n            }\n        }\n    }\n\n    /**\n     * 机器人功能测试\n     * <p>\n     * 测试以下功能：\n     * <ul>\n     * <li>创建机器人</li>\n     * <li>初始化RobotService（使用IM端口80）</li>\n     * <li>获取机器人信息</li>\n     * <li>发送消息</li>\n     * <li>撤回消息（仅商业版）</li>\n     * <li>更新消息（仅商业版）</li>\n     * <li>获取用户信息</li>\n     * <li>创建群组</li>\n     * <li>发送群组消息</li>\n     * <li>获取群组信息</li>\n     * <li>获取群组成员</li>\n     * <li>修改群组信息</li>\n     * <li>添加群成员</li>\n     * <li>踢出群成员</li>\n     * <li>退出群组</li>\n     * <li>解散群组</li>\n     * <li>销毁机器人</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testRobot() throws Exception {\n        String robotId = \"robot1\";\n        String robotSecret = \"123456\";\n        //初始化服务API\n        AdminConfig.initAdmin(AdminUrl, AdminSecret);\n        //创建机器人\n        InputCreateRobot createRobot = new InputCreateRobot();\n        createRobot.setUserId(robotId);\n        createRobot.setName(robotId);\n        createRobot.setDisplayName(\"机器人\");\n        createRobot.setOwner(\"userId1\");\n        createRobot.setSecret(robotSecret);\n        createRobot.setCallback(\"http://127.0.0.1:8883/robot/recvmsg\");\n        IMResult<OutputCreateRobot> resultCreateRobot = UserAdmin.createRobot(createRobot);\n        if (resultCreateRobot != null && resultCreateRobot.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Create robot \" + resultCreateRobot.getResult().getUserId() + \" success\");\n        } else {\n            System.out.println(\"Create robot failure\");\n            System.exit(-1);\n        }\n\n        //使用完需要释放\n        RobotService robotService = new RobotService(IMUrl, robotId, robotSecret);\n\n        //***********************************************\n        //****  机器人API\n        //***********************************************\n\n        IMResult<OutputRobot> robotProfileIMResult = robotService.getProfile();\n        if(robotProfileIMResult != null && robotProfileIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get profile success\");\n        } else {\n            System.out.println(\"get profile failure\");\n            System.exit(-1);\n        }\n\n        String displayName = \"testrobot\"+System.currentTimeMillis();\n        IMResult<Void> voidIMResult1 = robotService.updateProfile(Modify_DisplayName, displayName);\n        if(voidIMResult1 != null && voidIMResult1.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"modify profile success\");\n        } else {\n            System.out.println(\"modify profile failure\");\n            System.exit(-1);\n        }\n        robotProfileIMResult = robotService.getProfile();\n        if(robotProfileIMResult != null && robotProfileIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && displayName.equals(robotProfileIMResult.getResult().getDisplayName())) {\n            System.out.println(\"get profile success\");\n        } else {\n            System.out.println(\"get profile failure\");\n            System.exit(-1);\n        }\n\n        String robotCallback = \"http://hellow123\";\n        voidIMResult1 = robotService.setCallback(robotCallback);\n        if(voidIMResult1 != null && voidIMResult1.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"set callback success\");\n        } else {\n            System.out.println(\"set callback failure\");\n            System.exit(-1);\n        }\n\n        IMResult<RobotCallbackPojo> callbackPojoIMResult = robotService.getCallback();\n        if(callbackPojoIMResult != null && callbackPojoIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && robotCallback.equals(callbackPojoIMResult.getResult().getUrl())) {\n            System.out.println(\"get callback success\");\n        } else {\n            System.out.println(\"get callback failure\");\n            System.exit(-1);\n        }\n\n        //测试删除机器人回调地址\n        voidIMResult1 = robotService.deleteCallback();\n        if(voidIMResult1 != null && voidIMResult1.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"delete callback success\");\n        } else {\n            System.out.println(\"delete callback failure\");\n            System.exit(-1);\n        }\n\n        //验证回调地址已删除\n        callbackPojoIMResult = robotService.getCallback();\n        if(callbackPojoIMResult != null && callbackPojoIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && StringUtil.isNullOrEmpty(callbackPojoIMResult.getResult().getUrl())) {\n            System.out.println(\"get callback success\");\n        } else {\n            System.out.println(\"get callback failure\");\n            System.exit(-1);\n        }\n\n        //创建会话对象，设置目标用户和会话类型\n        Conversation conversation = new Conversation();\n        conversation.setTarget(\"user2\");\n        conversation.setType(ProtoConstants.ConversationType.ConversationType_Private);\n        \n        //创建消息payload，设置消息类型和内容\n        MessagePayload payload = new MessagePayload();\n        payload.setType(1);\n        payload.setSearchableContent(\"hello world\");\n\n        //测试机器人发送消息\n        IMResult<SendMessageResult> resultRobotSendMessage = robotService.sendMessage(robotService.getRobotId(), conversation, payload);\n        if (resultRobotSendMessage != null && resultRobotSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"robot send message success\");\n        } else {\n            System.out.println(\"robot send message failure\");\n            System.exit(-1);\n        }\n\n        //测试机器人回复消息\n        IMResult<SendMessageResult> replyMessageResult = robotService.replyMessage(resultRobotSendMessage.getResult().getMessageUid(), payload, false);\n        if (replyMessageResult != null && replyMessageResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"robot reply message success\");\n        } else {\n            System.out.println(\"robot reply message failure\");\n        }\n\n        if(commercialServer) {\n            Thread.sleep(1000);\n            IMResult<String> recallMessageResult = robotService.recallMessage(resultRobotSendMessage.result.getMessageUid());\n            if (recallMessageResult != null && recallMessageResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"robot recall message success\");\n            } else {\n                System.out.println(\"robot recall message failure\");\n                System.exit(-1);\n            }\n\n            payload.setSearchableContent(\"hello world, hello world\");\n            resultRobotSendMessage = robotService.sendMessage(robotService.getRobotId(), conversation, payload);\n            if (resultRobotSendMessage != null && resultRobotSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"robot send message success\");\n            } else {\n                System.out.println(\"robot send message failure\");\n                System.exit(-1);\n            }\n\n            Thread.sleep(1000);\n            payload.setSearchableContent(\"hello world, updated message content\");\n            IMResult<Void> updateMessageResult = robotService.updateMessage(resultRobotSendMessage.result.getMessageUid(), payload);\n            if (updateMessageResult != null && updateMessageResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"robot update message success\");\n            } else {\n                System.out.println(\"robot update message failure\");\n                System.exit(-1);\n            }\n        }\n\n\n        //测试机器人通过用户ID获取用户信息\n        IMResult<InputOutputUserInfo> resultRobotGetUserInfo = robotService.getUserInfo(\"userId1\");\n        if (resultRobotGetUserInfo != null && resultRobotGetUserInfo.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"robot get user info success\");\n        } else {\n            System.out.println(\"robot get user info by userId failure\");\n            System.exit(-1);\n        }\n\n        //测试机器人通过手机号获取用户信息\n        IMResult<InputOutputUserInfo> resultRobotGetUserInfoByMobile = robotService.getUserInfoByMobile(\"13900000000\");\n        if (resultRobotGetUserInfoByMobile != null && resultRobotGetUserInfoByMobile.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"robot get user info by mobile success\");\n        } else {\n            System.out.println(\"robot get user info by mobile failure\");\n        }\n\n        //测试机器人通过用户名获取用户信息\n        IMResult<InputOutputUserInfo> resultRobotGetUserInfoByName = robotService.getUserInfoByName(\"user1\");\n        if (resultRobotGetUserInfoByName != null && resultRobotGetUserInfoByName.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"robot get user info by name success\");\n        } else {\n            System.out.println(\"robot get user info by name failure\");\n        }\n\n        //创建群组信息，用于测试机器人群组管理功能\n        String groupId = \"robot_group\" + System.currentTimeMillis();\n        PojoGroupInfo groupInfo = new PojoGroupInfo();\n        groupInfo.setTarget_id(groupId);\n        groupInfo.setName(\"test_group\");\n        groupInfo.setType(2);\n        groupInfo.setExtra(\"hello extra\");\n        groupInfo.setPortrait(\"http://portrait\");\n        List<PojoGroupMember> members = new ArrayList<>();\n\n        PojoGroupMember member1 = new PojoGroupMember();\n        member1.setMember_id(\"user1\");\n        members.add(member1);\n\n        PojoGroupMember member2 = new PojoGroupMember();\n        member2.setMember_id(\"user2\");\n        members.add(member2);\n\n        PojoGroupMember member3 = new PojoGroupMember();\n        member3.setMember_id(\"user3\");\n        members.add(member3);\n\n        //测试机器人创建群组\n        IMResult<OutputCreateGroupResult> resultCreateGroup = robotService.createGroup(groupInfo, members, null, null, null);\n        if (resultCreateGroup != null && resultCreateGroup.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"create group success\");\n        } else {\n            System.out.println(\"create group failure\");\n            System.exit(-1);\n        }\n\n        IMResult<PojoGroupInfo> resultGetGroupInfo = robotService.getGroupInfo(groupInfo.getTarget_id());\n        if (resultGetGroupInfo != null && resultGetGroupInfo.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (groupInfo.getExtra().equals(resultGetGroupInfo.getResult().getExtra())\n                && groupInfo.getName().equals(resultGetGroupInfo.getResult().getName())\n                && robotId.equals(resultGetGroupInfo.getResult().getOwner())) {\n                System.out.println(\"get group success\");\n            } else {\n                System.out.println(\"group info is not expected\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"create group failure\");\n            System.exit(-1);\n        }\n\n        IMResult<Void> voidIMResult = robotService.modifyGroupInfo(groupInfo.getTarget_id(), ProtoConstants.ModifyGroupInfoType.Modify_Group_Name,\"HelloWorld\", null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"modify group success\");\n        } else {\n            System.out.println(\"modify group failure\");\n            System.exit(-1);\n        }\n\n\n        IMResult<OutputGroupMemberList> resultGetMembers = robotService.getGroupMembers(groupInfo.getTarget_id());\n        if (resultGetMembers != null && resultGetMembers.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get group member success\");\n        } else {\n            System.out.println(\"get group member failure\");\n            System.exit(-1);\n        }\n\n        PojoGroupMember m = new PojoGroupMember();\n        m.setMember_id(\"user0\");\n        m.setAlias(\"hello user0\");\n\n        voidIMResult = robotService.addGroupMembers(groupInfo.getTarget_id(), Arrays.asList(m), null, null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"add group member success\");\n        } else {\n            System.out.println(\"add group member failure\");\n            System.exit(-1);\n        }\n\n        IMResult<PojoGroupMember> groupMemberIMResult = robotService.getGroupMember(groupInfo.getTarget_id(), \"user0\");\n        if (groupMemberIMResult != null && groupMemberIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get group member success\");\n        } else {\n            System.out.println(\"get group member failure\");\n            System.exit(-1);\n        }\n\n        voidIMResult = robotService.kickoffGroupMembers(groupInfo.getTarget_id(), Arrays.asList(\"user3\"), null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"kickoff group member success\");\n        } else {\n            System.out.println(\"kickoff group member failure\");\n            System.exit(-1);\n        }\n\n        voidIMResult = robotService.setGroupMemberAlias(groupInfo.getTarget_id(), \"user2\", \"test user2\", null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"set group member alias success\");\n        } else {\n            System.out.println(\"set group member alias failure\");\n            System.exit(-1);\n        }\n\n        //测试设置群成员extra\n        voidIMResult = robotService.setGroupMemberExtra(groupInfo.getTarget_id(), \"user2\", \"robot member extra\", null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"set group member extra success\");\n        } else {\n            System.out.println(\"set group member extra failure\");\n            System.exit(-1);\n        }\n\n        if(commercialServer) {\n            PojoGroupMember m4 = new PojoGroupMember();\n            m4.setMember_id(\"user4\");\n            m4.setAlias(\"hello user4\");\n\n            PojoGroupMember m5 = new PojoGroupMember();\n            m5.setMember_id(\"user5\");\n            m5.setAlias(\"hello user5\");\n\n            voidIMResult = robotService.addGroupMembers(groupInfo.getTarget_id(), Arrays.asList(m4, m5), null, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"add group member success\");\n            } else {\n                System.out.println(\"add group member failure\");\n                System.exit(-1);\n            }\n\n            voidIMResult = robotService.setGroupManager(groupInfo.getTarget_id(), Arrays.asList(\"user4\", \"user5\"), true, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"set group manager success\");\n            } else {\n                System.out.println(\"set group manager failure\");\n                System.exit(-1);\n            }\n\n            voidIMResult = robotService.setGroupManager(groupInfo.getTarget_id(), Arrays.asList(\"user4\", \"user5\"), false, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"cancel group manager success\");\n            } else {\n                System.out.println(\"cancel group manager failure\");\n                System.exit(-1);\n            }\n\n\n            //测试机器人应用获取用户信息。authCode应该是从客户端SDK里获取到的，这里不具备条件，跳过测试\n//            IMResult<OutputApplicationUserInfo> appGetUserInfoResult = robotService.applicationGetUserInfo(\"test_auth_code\");\n//            if (appGetUserInfoResult != null && (appGetUserInfoResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS || appGetUserInfoResult.getErrorCode() == ErrorCode.ERROR_CODE_INVALID_DATA)) {\n//                System.out.println(\"robot application get user info success\");\n//            } else {\n//                System.out.println(\"robot application get user info failure\");\n//            }\n\n            //测试机器人发送会议请求。不具备测试条件，注释掉。\n//            IMResult<String> sendConferenceRequestResult = robotService.sendConferenceRequest(robotId, \"client1\", \"test_request\", 1, \"room1\", \"test_data\", false);\n//            if (sendConferenceRequestResult != null && (sendConferenceRequestResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS || sendConferenceRequestResult.getErrorCode() == ErrorCode.ERROR_CODE_INVALID_DATA)) {\n//                System.out.println(\"robot send conference request success\");\n//            } else {\n//                System.out.println(\"robot send conference request failure\");\n//            }\n\n            OutputApplicationConfigData config = robotService.getApplicationSignature();\n            System.out.println(config);\n        }\n\n        //仅专业版支持\n        if (commercialServer) {\n            //开启群成员禁言\n            voidIMResult = robotService.muteGroupMember(groupInfo.getTarget_id(), Arrays.asList(\"user5\"), true, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"mute group member success\");\n            } else {\n                System.out.println(\"mute group member failure\");\n                System.exit(-1);\n            }\n            //关闭群成员禁言\n            voidIMResult = robotService.muteGroupMember(groupInfo.getTarget_id(), Arrays.asList(\"user5\"), false, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"unmute group member success\");\n            } else {\n                System.out.println(\"unmute group member failure\");\n                System.exit(-1);\n            }\n\n            //开启群成员白名单，当群全局禁言时，白名单用户可以发言\n            voidIMResult = robotService.allowGroupMember(groupInfo.getTarget_id(), Arrays.asList(\"user5\"), true, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"allow group member success\");\n            } else {\n                System.out.println(\"allow group member failure\");\n                System.exit(-1);\n            }\n\n            //关闭群成员白名单\n            voidIMResult = robotService.allowGroupMember(groupInfo.getTarget_id(), Arrays.asList(\"user5\"), false, null, null);\n            if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"unallow group member success\");\n            } else {\n                System.out.println(\"unallow group member failure\");\n                System.exit(-1);\n            }\n        }\n        //测试机器人转让群组给user2\n        voidIMResult = robotService.transferGroup(groupInfo.getTarget_id(), \"user2\", null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"transfer success\");\n        } else {\n            System.out.println(\"create group failure\");\n            System.exit(-1);\n        }\n\n        //验证群组转让成功，检查新群主是否为user2\n        resultGetGroupInfo = robotService.getGroupInfo(groupInfo.getTarget_id());\n        if (resultGetGroupInfo != null && resultGetGroupInfo.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            if (\"user2\".equals(resultGetGroupInfo.getResult().getOwner())) {\n                groupInfo.setOwner(\"user2\");\n            } else {\n                System.out.println(\"group info is not expected\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"create group failure\");\n            System.exit(-1);\n        }\n\n        //测试机器人退出群组\n        voidIMResult = robotService.quitGroup(groupInfo.getTarget_id(), null, null);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"quit group success\");\n        } else {\n            System.out.println(\"quit group failure\");\n            System.exit(-1);\n        }\n\n        //仅专业版支持，且服务器端支持朋友圈\n        if (robotMomentsEnabled) {\n            IMResult<FeedPojo> postResult = robotService.postMomentsFeed(ProtoConstants.MomentsContentType.Moments_Content_Text_Type, \"hello from robot\", null, null, null, null, \"hello_extra\");\n            if (postResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"post moments feed success\");\n            } else {\n                System.out.println(\"post moments feed failure:\" + postResult.getErrorCode().code);\n                System.exit(-1);\n            }\n\n            IMResult<FeedsPojo> pullResult = robotService.getMomentsFeeds(0, 10, null);\n            if (pullResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"pull moments feeds success\");\n            } else {\n                System.out.println(\"pull moments feeds failure:\" + pullResult.getErrorCode().code);\n                System.exit(-1);\n            }\n\n            IMResult<FeedPojo> feedResult = robotService.getMomentsFeed(postResult.getResult().feedId);\n            if (feedResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"pull moments one feed success\");\n            } else {\n                System.out.println(\"pull moments one feed failure:\" + feedResult.getErrorCode().code);\n                System.exit(-1);\n            }\n\n            IMResult<CommentPojo> commentThumbUpResult = robotService.postMomentsComment(postResult.result.feedId, 0, ProtoConstants.MomentsCommentType.Moments_Comment_Thumbup_Type, null, null, null);\n            if (commentThumbUpResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"post moments thumb up success\");\n            } else {\n                System.out.println(\"post moments thumb up failure:\" + commentThumbUpResult.getErrorCode().code);\n                System.exit(-1);\n            }\n\n            IMResult<CommentPojo> commentTextResult = robotService.postMomentsComment(postResult.result.feedId, 0, ProtoConstants.MomentsCommentType.Moments_Comment_Text_Type, \"comment hello\", null, null);\n            if (commentTextResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"post moments comment text success\");\n            } else {\n                System.out.println(\"post moments comment text failure:\" + commentTextResult.getErrorCode().code);\n                System.exit(-1);\n            }\n\n            IMResult<Void> updateResult = robotService.updateMomentsFeed(postResult.getResult().feedId, ProtoConstants.MomentsContentType.Moments_Content_Text_Type, \"hello from robot2\", null, null, null, null, \"hello_extra2\");\n            if (updateResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"update moments feed success\");\n            } else {\n                System.out.println(\"update moments feed failure:\" + updateResult.getErrorCode().code);\n                System.exit(-1);\n            }\n\n            IMResult<Void> deleteCommentThumbUpResult = robotService.deleteMomentsComment(postResult.result.feedId, commentThumbUpResult.result.commentId);\n            if (deleteCommentThumbUpResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"delete moments thumb up success\");\n            } else {\n                System.out.println(\"delete moments thumb up failure:\" + deleteCommentThumbUpResult.getErrorCode().code);\n                System.exit(-1);\n            }\n\n            IMResult<Void> deleteCommentTextResult = robotService.deleteMomentsComment(postResult.result.feedId, commentTextResult.result.commentId);\n            if (deleteCommentTextResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"delete moments comment text success\");\n            } else {\n                System.out.println(\"delete moments comment text failure:\" + deleteCommentTextResult.getErrorCode().code);\n                System.exit(-1);\n            }\n\n            IMResult<Void> deleteFeedResult = robotService.deleteMomentsFeed(postResult.result.feedId);\n            if (deleteFeedResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"delete moments feed success\");\n            } else {\n                System.out.println(\"delete moments feed failure:\" + deleteFeedResult.getErrorCode().code);\n                System.exit(-1);\n            }\n\n            IMResult<MomentProfilePojo> profileResult = robotService.getUserMomentsProfile(robotId);\n            if (profileResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"get user moments profile success\");\n            } else {\n                System.out.println(\"get user moments profile failure:\" + profileResult.getErrorCode().code);\n                System.exit(-1);\n            }\n\n            //测试更新朋友圈设置\n            IMResult<Void> updateBgResult = robotService.updateMomentsBackgroundUrl(\"https://example.com/bg.jpg\");\n            if (updateBgResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"update moments background success\");\n            } else {\n                System.out.println(\"update moments background failure:\" + updateBgResult.getErrorCode().code);\n            }\n\n            IMResult<Void> updateVisibleCountResult = robotService.updateMomentsStrangerVisibleCount(10);\n            if (updateVisibleCountResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"update moments visible count success\");\n            } else {\n                System.out.println(\"update moments visible count failure:\" + updateVisibleCountResult.getErrorCode().code);\n            }\n\n            IMResult<Void> updateVisibleScopeResult = robotService.updateMomentsVisibleScope(0);\n            if (updateVisibleScopeResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"update moments visible scope success\");\n            } else {\n                System.out.println(\"update moments visible scope failure:\" + updateVisibleScopeResult.getErrorCode().code);\n            }\n\n            IMResult<Void> updateBlackListResult = robotService.updateMomentsBlackList(Arrays.asList(\"user1\"), null);\n            if (updateBlackListResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"update moments blacklist success\");\n            } else {\n                System.out.println(\"update moments blacklist failure:\" + updateBlackListResult.getErrorCode().code);\n            }\n\n            IMResult<Void> updateBlockListResult = robotService.updateMomentsBlockList(Arrays.asList(\"user2\"), null);\n            if (updateBlockListResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"update moments blocklist success\");\n            } else {\n                System.out.println(\"update moments blocklist failure:\" + updateBlockListResult.getErrorCode().code);\n            }\n        }\n\n        //释放机器人服务资源\n        robotService.close();\n    }\n\n    //***测试频道API功能，仅专业版支持***\n    /**\n     * 频道功能测试（仅专业版支持）\n     * <p>\n     * 测试以下功能：\n     * <ul>\n     * <li>创建频道</li>\n     * <li>获取频道信息</li>\n     * <li>修改频道信息</li>\n     * <li>获取频道列表</li>\n     * <li>关注/取消关注频道</li>\n     * <li>获取频道关注者</li>\n     * <li>设置频道菜单</li>\n     * <li>获取频道菜单</li>\n     * <li>发送频道消息</li>\n     * <li>获取频道历史消息</li>\n     * <li>获取用户关注的频道</li>\n     * <li>删除频道（标记为已删除）</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testChannel() throws Exception {\n        //初始化服务API\n        AdminConfig.initAdmin(AdminUrl, AdminSecret);\n\n        //先创建3个用户\n        InputOutputUserInfo userInfo = new InputOutputUserInfo();\n        userInfo.setUserId(\"userId1\");\n        userInfo.setName(\"user1\");\n        userInfo.setMobile(\"13900000000\");\n        userInfo.setDisplayName(\"user 1\");\n\n        IMResult<OutputCreateUser> resultCreateUser = UserAdmin.createUser(userInfo);\n        if (resultCreateUser != null && resultCreateUser.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Create user \" + resultCreateUser.getResult().getName() + \" success\");\n        } else {\n            System.out.println(\"Create user failure\");\n            System.exit(-1);\n        }\n\n        userInfo = new InputOutputUserInfo();\n        userInfo.setUserId(\"userId2\");\n        userInfo.setName(\"user2\");\n        userInfo.setMobile(\"13900000002\");\n        userInfo.setDisplayName(\"user 2\");\n\n        resultCreateUser = UserAdmin.createUser(userInfo);\n        if (resultCreateUser != null && resultCreateUser.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Create user \" + resultCreateUser.getResult().getName() + \" success\");\n        } else {\n            System.out.println(\"Create user failure\");\n            System.exit(-1);\n        }\n\n        userInfo = new InputOutputUserInfo();\n        userInfo.setUserId(\"userId3\");\n        userInfo.setName(\"user3\");\n        userInfo.setMobile(\"13900000003\");\n        userInfo.setDisplayName(\"user 3\");\n\n        resultCreateUser = UserAdmin.createUser(userInfo);\n        if (resultCreateUser != null && resultCreateUser.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Create user \" + resultCreateUser.getResult().getName() + \" success\");\n        } else {\n            System.out.println(\"Create user failure\");\n            System.exit(-1);\n        }\n\n        //1. 先使用admin api创建频道\n        InputCreateChannel inputCreateChannel = new InputCreateChannel();\n        inputCreateChannel.setName(\"testChannel\");\n        inputCreateChannel.setOwner(\"userId1\");\n        String secret = \"channelsecret\";\n        String channelId = \"channelId123\";\n        inputCreateChannel.setSecret(secret);\n        inputCreateChannel.setTargetId(channelId);\n        inputCreateChannel.setAuto(1);\n        inputCreateChannel.setCallback(\"http://192.168.1.81:8088/wf/channelId123\");\n        inputCreateChannel.setState(Channel_State_Mask_FullInfo | Channel_State_Mask_Unsubscribed_User_Access | Channel_State_Mask_Active_Subscribe | Channel_State_Mask_Message_Unsubscribed);\n        IMResult<OutputCreateChannel> resultCreateChannel = ChannelAdmin.createChannel(inputCreateChannel);\n        if (resultCreateChannel != null && resultCreateChannel.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"create channel success\");\n        } else {\n            System.out.println(\"create channel failure\");\n            System.exit(-1);\n        }\n\n\n        //2. 初始化api，注意端口是80，不是18080 //使用完需要释放\n        ChannelServiceApi channelServiceApi = new ChannelServiceApi(IMUrl, channelId, secret);\n\n\n        //3. 测试channel api功能\n        \n        //测试用户关注频道\n        IMResult<Void> resultVoid = channelServiceApi.subscribe(\"userId2\");\n        if (resultVoid != null && resultVoid.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"subscribe success\");\n        } else {\n            System.out.println(\"subscribe failure\");\n            System.exit(-1);\n        }\n\n        //测试另一个用户关注频道\n        resultVoid = channelServiceApi.subscribe(\"userId3\");\n        if (resultVoid != null && resultVoid.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"subscribe done\");\n        } else {\n            System.out.println(\"subscribe failure\");\n            System.exit(-1);\n        }\n\n        //使用Admin API让userId4关注频道\n        resultVoid = ChannelAdmin.subscribeChannel(channelId, \"userId4\");\n        if (resultVoid != null && resultVoid.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"subscribe done\");\n        } else {\n            System.out.println(\"subscribe failure\");\n            System.exit(-1);\n        }\n\n        //获取频道订阅者列表\n        IMResult<OutputStringList> resultStringList = channelServiceApi.getSubscriberList();\n        if (resultStringList != null && resultStringList.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && resultStringList.getResult().getList().contains(\"userId2\") && resultStringList.getResult().getList().contains(\"userId3\") && resultStringList.getResult().getList().contains(\"userId4\")) {\n            System.out.println(\"get subscriber done\");\n        } else {\n            System.out.println(\"get subscriber failure\");\n            System.exit(-1);\n        }\n\n        //检查用户是否订阅了频道\n        IMResult<Boolean> booleanIMResult = channelServiceApi.isSubscriber(\"userId2\");\n        if(booleanIMResult != null && booleanIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && booleanIMResult.getResult()) {\n            System.out.println(\"is subscriber success\");\n        } else {\n            System.out.println(\"is subscriber failure\");\n            System.exit(-1);\n        }\n\n        //测试用户取消关注频道\n        resultVoid = channelServiceApi.unsubscribe(\"userId2\");\n        if (resultVoid != null && resultVoid.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"unsubscriber done\");\n        } else {\n            System.out.println(\"unsubscriber failure\");\n            System.exit(-1);\n        }\n\n        //验证userId2已不在订阅者列表中\n        resultStringList = channelServiceApi.getSubscriberList();\n        if (resultStringList != null && resultStringList.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && resultStringList.getResult().getList().contains(\"userId3\") && !resultStringList.getResult().getList().contains(\"userId2\")) {\n            System.out.println(\"get subscriber done\");\n        } else {\n            System.out.println(\"get subscriber failure\");\n            System.exit(-1);\n        }\n\n        //测试频道获取用户信息\n        IMResult<InputOutputUserInfo> resultGetUserInfo1 = channelServiceApi.getUserInfo(\"userId3\");\n        if (resultGetUserInfo1 != null && resultGetUserInfo1.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get user info success\");\n        } else {\n            System.out.println(\"get user info failure\");\n            System.exit(-1);\n        }\n\n        //创建消息payload\n        MessagePayload payload = new MessagePayload();\n        payload.setType(1);\n        payload.setSearchableContent(\"hello world\");\n\n        IMResult<SendMessageResult> resultSendMessage = channelServiceApi.sendMessage(0, null, payload);\n        if (resultSendMessage != null && resultSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"send message to all the subscriber success\");\n        } else {\n            System.out.println(\"send message to all the subscriber  failure\");\n            System.exit(-1);\n        }\n\n        //测试重新发布消息\n        IMResult<Void> republishResult = channelServiceApi.republishMessage(resultSendMessage.getResult().getMessageUid(), Arrays.asList(\"userId2\", \"userId3\"));\n        if (republishResult != null && republishResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"republish message success\");\n        } else {\n            System.out.println(\"republish message failure\");\n            System.exit(-1);\n        }\n\n        ArticleContent articleContent = new ArticleContent(\"article1\", \"https://media.wfcoss.cn/channel-assets/20220816/2dd76540daa9444dae44e942aa1c2bbc.png\", \"这是一个测试文章\", \"测试一下文章的功能\", \"https://mp.weixin.qq.com/s/W6tanLbALd3qqZM8r3MTgA\", true);\n        articleContent.addSubArticle(\"article2\", \"https://media.wfcoss.cn/channel-assets/20220816/2dd76540daa9444dae44e942aa1c2bbc.png\", \"这是第二个测试文章\", \"测试一下文章的功能\", \"https://mp.weixin.qq.com/s/W6tanLbALd3qqZM8r3MTgA\", false);\n        articleContent.addSubArticle(\"article3\", \"https://media.wfcoss.cn/channel-assets/20220816/2dd76540daa9444dae44e942aa1c2bbc.png\", \"这是第三个测试文章\", \"测试一下文章的功能\", \"https://mp.weixin.qq.com/s/W6tanLbALd3qqZM8r3MTgA\", false);\n        payload = articleContent.toPayload();\n\n        resultSendMessage = channelServiceApi.sendMessage(0, null, payload);\n        if (resultSendMessage != null && resultSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"send message to all the subscriber success\");\n        } else {\n            System.out.println(\"send message to all the subscriber  failure\");\n            System.exit(-1);\n        }\n\n        //发送定向消息给指定用户\n        payload.setSearchableContent(\"hello to user2\");\n\n        resultSendMessage = channelServiceApi.sendMessage(0, Arrays.asList(\"userId2\"),payload);\n        if (resultSendMessage != null && resultSendMessage.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"send message to user2 success\");\n        } else {\n            System.out.println(\"send message to user2 failure\");\n            System.exit(-1);\n        }\n\n        //测试修改频道描述信息\n        IMResult<Void> voidIMResult = channelServiceApi.modifyChannelInfo(ProtoConstants.ModifyChannelInfoType.Modify_Channel_Desc, \"this is a test channel, update at:\" + new Date().toString());\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"modify channel profile success\");\n        } else {\n            System.out.println(\"modify channel profile failure\");\n            System.exit(-1);\n        }\n\n        List<PojoChannelMenu> menus = new ArrayList<>();\n        PojoChannelMenu menu1 = new PojoChannelMenu();\n        menu1.menuId = UUID.randomUUID().toString();\n        menu1.type = \"view\";\n        menu1.name = \"一级菜单1\";\n        menu1.key = \"key1\";\n        menu1.url = \"http://www.baidu.com\";\n        menus.add(menu1);\n\n        PojoChannelMenu menu2 = new PojoChannelMenu();\n        menu2.menuId = UUID.randomUUID().toString();\n        menu2.type = \"view\";\n        menu2.name = \"一级菜单2\";\n        menu2.key = \"key2\";\n        menu2.url = \"http://www.sohu.com\";\n        menu2.subMenus = new ArrayList<>();\n        menus.add(menu2);\n\n        PojoChannelMenu menu21 = new PojoChannelMenu();\n        menu21.menuId = UUID.randomUUID().toString();\n        menu21.type = \"click\";\n        menu21.name = \"二级菜单21\";\n        menu21.key = \"key21\";\n        menu21.url = \"http://www.sohu.com\";\n        menu2.subMenus.add(menu21);\n\n        String menuStr = new GsonBuilder().disableHtmlEscaping().create().toJson(menus);\n        voidIMResult = channelServiceApi.modifyChannelInfo(ProtoConstants.ModifyChannelInfoType.Modify_Channel_Menu, menuStr);\n        if (voidIMResult != null && voidIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"modify channel menu success\");\n        } else {\n            System.out.println(\"modify channel menu failure\");\n            System.exit(-1);\n        }\n\n        IMResult<OutputGetChannelInfo> outputGetChannelInfoIMResult = channelServiceApi.getChannelInfo();\n        if (outputGetChannelInfoIMResult != null && outputGetChannelInfoIMResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get channel info success\");\n        } else {\n            System.out.println(\"get channel info failure\");\n            System.exit(-1);\n        }\n\n        //测试修改频道菜单\n        List<PojoChannelMenu> testMenus = new ArrayList<>();\n        PojoChannelMenu testMenu = new PojoChannelMenu();\n        testMenu.menuId = UUID.randomUUID().toString();\n        testMenu.type = \"view\";\n        testMenu.name = \"测试菜单\";\n        testMenu.key = \"test_key\";\n        testMenu.url = \"http://www.test.com\";\n        testMenus.add(testMenu);\n        IMResult<Void> modifyMenuResult = channelServiceApi.modifyChannelMenu(testMenus);\n        if (modifyMenuResult != null && modifyMenuResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"modify channel menu success\");\n        } else {\n            System.out.println(\"modify channel menu failure\");\n        }\n        OutputApplicationConfigData config = channelServiceApi.getApplicationSignature();\n        System.out.println(config);\n\n        //使用完需要释放\n        channelServiceApi.close();\n    }\n\n    /**\n     * 敏感词管理API测试\n     * <p>\n     * 测试以下功能：\n     * <ul>\n     * <li>添加敏感词到敏感词库</li>\n     * <li>获取敏感词列表</li>\n     * <li>从敏感词库移除敏感词</li>\n     * <li>验证敏感词添加和移除操作</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testSensitiveApi() throws Exception {\n        List<String> words = Arrays.asList(\"a\",\"b\",\"c\");\n        IMResult<Void> addResult = SensitiveAdmin.addSensitives(words);\n        if (addResult != null && addResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Add sensitive word response success\");\n        } else {\n            System.out.println(\"Add sensitive word response error\");\n            System.exit(-1);\n        }\n\n        Thread.sleep(100);\n\n        IMResult<InputOutputSensitiveWords> swResult = SensitiveAdmin.getSensitives();\n        if (swResult != null && swResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && swResult.getResult().getWords().containsAll(words)) {\n            System.out.println(\"Sensitive word added\");\n        } else {\n            System.out.println(\"Sensitive word not added\");\n            System.exit(-1);\n        }\n\n        IMResult<Void> removeResult = SensitiveAdmin.removeSensitives(words);\n        if (removeResult != null && removeResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Remove sensitive word response success\");\n        } else {\n            System.out.println(\"Remove sensitive word response error\");\n            System.exit(-1);\n        }\n\n        Thread.sleep(100);\n        swResult = SensitiveAdmin.getSensitives();\n        if (swResult != null && swResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && !swResult.getResult().getWords().containsAll(words)) {\n            System.out.println(\"Sensitive word removed\");\n        } else {\n            System.out.println(\"Sensitive word not removed\");\n            System.exit(-1);\n        }\n    }\n\n    /**\n     * 朋友圈（动态）API测试\n     * <p>\n     * 测试以下功能：\n     * <ul>\n     * <li>发布动态（朋友圈）</li>\n     * <li>发送文本动态内容</li>\n     * <li>验证动态发送结果</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testMomentsApi() throws Exception {\n        FeedPojo feedPojo = new FeedPojo();\n        feedPojo.sender = \"73055b4105de4b70993b7258afbfc387\";\n        feedPojo.type = 0;\n        feedPojo.text = \"hello from admin\";\n        IMResult<SendMessageResult> sendResult = MomentsAdmin.postFeeds(feedPojo);\n        if (sendResult != null && sendResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"send moments feed success\");\n        } else {\n            System.out.println(\"send moments feed failure\");\n            System.exit(-1);\n        }\n    }\n\n    //***********************************************\n    //****  物联网相关的API，仅专业版支持\n    //***********************************************\n    /**\n     * 物联网设备管理API测试（仅专业版支持）\n     * <p>\n     * 测试以下功能：\n     * <ul>\n     * <li>创建或更新设备</li>\n     * <li>获取设备信息</li>\n     * <li>设备绑定多个所有者</li>\n     * <li>设备ID唯一性验证</li>\n     * <li>销毁设备</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testDevice() throws Exception {\n        //创建设备信息，设置设备ID和所有者列表\n        InputCreateDevice createDevice = new InputCreateDevice();\n        createDevice.setDeviceId(\"deviceId1\");\n        createDevice.setOwners(Arrays.asList(\"opoGoG__\", \"userId1\"));\n        \n        //测试创建设备（如果不存在则创建，存在则更新）\n        IMResult<OutputCreateDevice> resultCreateDevice = UserAdmin.createOrUpdateDevice(createDevice);\n        if (resultCreateDevice != null && resultCreateDevice.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"Create device \" + resultCreateDevice.getResult().getDeviceId() + \" success\");\n        } else {\n            System.out.println(\"Create device failure\");\n            System.exit(-1);\n        }\n\n        //测试获取设备信息\n        IMResult<OutputDevice> getDevice = UserAdmin.getDevice(\"deviceId1\");\n        if (getDevice != null && getDevice.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS && getDevice.getResult().getDeviceId().equals(\"deviceId1\") && getDevice.getResult().getOwners().contains(\"opoGoG__\")) {\n            System.out.println(\"Get device \" + resultCreateDevice.getResult().getDeviceId() + \" success\");\n        } else {\n            System.out.println(\"Get device failure\");\n            System.exit(-1);\n        }\n\n        //测试获取用户绑定的所有设备\n        IMResult<OutputDeviceList> getUserDevices = UserAdmin.getUserDevices(\"userId1\");\n        if (getUserDevices != null && getUserDevices.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            boolean success = false;\n            for (OutputDevice outputDevice : getUserDevices.getResult().getDevices()) {\n                if (outputDevice.getDeviceId().equals(\"deviceId1\")) {\n                    success = true;\n                    break;\n                }\n            }\n            if (success) {\n                System.out.println(\"Get user device success\");\n            } else {\n                System.out.println(\"Get user device failure\");\n                System.exit(-1);\n            }\n        } else {\n            System.out.println(\"Get device failure\");\n            System.exit(-1);\n        }\n    }\n\n    /**\n     * 会议功能测试（仅音视频高级版服务支持）\n     * <p>\n     * 测试以下会议功能：\n     * <ul>\n     * <li>获取会议列表</li>\n     * <li>销毁会议</li>\n     * <li>创建普通会议</li>\n     * <li>创建高级会议</li>\n     * <li>检查会议是否存在</li>\n     * <li>开启会议录制</li>\n     * <li>获取参会者列表</li>\n     * <li>RTP转发相关操作</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    public static void testConference() throws Exception {\n        //获取当前会议列表\n        IMResult<PojoConferenceInfoList> listResult = ConferenceAdmin.listConferences(100, 0);\n        if(listResult == null || listResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get conference list failure\");\n            System.exit(-1);\n        } else {\n            System.out.println(\"conference list \" + listResult.getResult().conferenceInfoList);\n        }\n\n        //清理现有会议，避免影响测试\n        for (PojoConferenceInfo conferenceInfo:listResult.getResult().conferenceInfoList) {\n            IMResult<Void> destroyResult = ConferenceAdmin.destroy(conferenceInfo.roomId, conferenceInfo.advance);\n            if(destroyResult == null || destroyResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"destroy room failure\");\n                System.exit(-1);\n            } else {\n                System.out.println(\"destroy room success\");\n            }\n        }\n\n        //再次获取会议列表，确认已清空\n        listResult = ConferenceAdmin.listConferences(100, 0);\n        if(listResult == null || listResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get conference list failure\");\n            System.exit(-1);\n        } else {\n            System.out.println(\"conference list \" + listResult.getResult().conferenceInfoList);\n        }\n\n        //生成两个会议房间ID\n        String roomId1 = UUID.randomUUID().toString();\n        String roomId2 = UUID.randomUUID().toString();\n        //创建普通会议房间（非高级版，最多9人）\n        IMResult<Void> voidIMResult = ConferenceAdmin.createRoom(roomId1, \"hello room description\", \"123456\", 9, false, 0, false, true);\n        if(voidIMResult == null || voidIMResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"create conference failure\");\n            System.exit(-1);\n        } else {\n            System.out.println(\"create conference\");\n        }\n\n        //创建高级会议房间（支持更多功能，最多20人）\n        voidIMResult = ConferenceAdmin.createRoom(roomId2, \"hello room description advanced\", \"123456\", 20, true, 0, false, true);\n        if(voidIMResult == null || voidIMResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"create conference failure\");\n            System.exit(-1);\n        } else {\n            System.out.println(\"create conference\");\n        }\n\n        //检查会议房间是否存在\n        IMResult<Boolean> booleanIMResult = ConferenceAdmin.existsConferences(roomId1);\n        if(booleanIMResult == null || booleanIMResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"exist conference failure\");\n            System.exit(-1);\n        } else {\n            System.out.println(\"exit conference success\");\n        }\n\n        //开启会议录制功能（视频和音频都录制）\n        voidIMResult = ConferenceAdmin.enableRecording(roomId2, true, true);\n        if(voidIMResult == null || voidIMResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"recording conference failure\");\n            System.exit(-1);\n        } else {\n            System.out.println(\"recording conference success\");\n        }\n\n        listResult = ConferenceAdmin.listConferences(100, 0);\n        if(listResult == null || listResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"get conference list failure\");\n            System.exit(-1);\n        } else {\n            System.out.println(\"conference list \" + listResult.getResult().conferenceInfoList);\n        }\n\n        //获取每个会议的参会者列表\n        for (PojoConferenceInfo conferenceInfo:listResult.getResult().conferenceInfoList) {\n            IMResult<PojoConferenceParticipantList> listParticipantsResult = ConferenceAdmin.listParticipants(conferenceInfo.roomId, conferenceInfo.advance);\n            if(listParticipantsResult == null || listParticipantsResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"list participants failure\");\n                System.exit(-1);\n            } else {\n                System.out.println(\"list participants success\");\n            }\n        }\n\n        //获取RTP转发器列表，并停止所有转发\n        IMResult<PojoConferenceRtpForwarders> listForwarderResult = ConferenceAdmin.listRtpForwarders(\"6366963312\");\n        if(listForwarderResult == null || listForwarderResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"list rtp forward failure\");\n        } else {\n            System.out.println(\"list rtp forward success\");\n            listForwarderResult.getResult().forwarders.forEach(rtpForwarder -> rtpForwarder.streams.forEach(rtpStream -> {\n                try {\n                    IMResult<Void> stopRtpForwardResult = ConferenceAdmin.stopRtpForward(listForwarderResult.getResult().roomId, rtpForwarder.publisherId, rtpStream.streamId);\n                    if(stopRtpForwardResult == null || stopRtpForwardResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n                        System.out.println(\"rtp forward stop failure\");\n                    } else {\n                        System.out.println(\"rtp forward stop success\");\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }));\n        }\n\n        //测试RTP转发功能，将媒体流转发到指定地址\n        IMResult<Void> rtpForwardResult = ConferenceAdmin.rtpForward(\"6366963312\", \"cygqmws2k\", \"192.168.1.81\", 10000, 111, 0, 10005, 98, 0);\n        if(rtpForwardResult == null || rtpForwardResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"rtp forward failure\");\n        } else {\n            System.out.println(\"rtp forward success\");\n        }\n    }\n\n    //***********************************************\n    //****  Mesh相关API，用于分布式IM\n    //***********************************************\n    /**\n     * Mesh（分布式IM）API测试\n     * <p>\n     * 测试以下分布式IM功能：\n     * <ul>\n     * <li>搜索用户 - 跨域搜索用户</li>\n     * <li>批量获取用户信息 - 获取多个用户的详细信息</li>\n     * <li>发送好友请求 - 向其他域用户发送好友请求</li>\n     * <li>处理好友请求 - 接受或拒绝好友请求</li>\n     * <li>创建域 - 创建新的Mesh域</li>\n     * <li>获取域信息 - 获取指定域的详细信息</li>\n     * <li>获取所有域 - 获取Mesh网络中的所有域列表</li>\n     * <li>Ping域 - 测试域的连通性</li>\n     * <li>删除域 - 从Mesh网络中移除域</li>\n     * <li>同步群组 - 跨域同步群组信息</li>\n     * <li>发送消息 - 向其他域用户发送消息</li>\n     * <li>发布消息 - 向多个域用户广播消息</li>\n     * <li>添加加入群组请求 - 跨域申请加入群组</li>\n     * <li>会议用户请求 - 跨域会议相关请求</li>\n     * <li>会议用户事件 - 跨域会议事件处理</li>\n     * </ul>\n     * </p>\n     * @throws Exception 当测试过程中发生错误时抛出异常\n     */\n    static void testMesh() throws Exception {\n        //测试搜索用户\n        IMResult<PojoSearchUserRes> searchUserResult = MeshAdmin.searchUser(\"test\", 0, 0, 1);\n        if (searchUserResult != null && searchUserResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh search user success\");\n        } else {\n            System.out.println(\"mesh search user failure\");\n        }\n\n        //测试批量获取用户信息\n        IMResult<OutputUserInfoList> batchUserInfosResult = MeshAdmin.getBatchUserInfos(Arrays.asList(\"user1\", \"user2\"));\n        if (batchUserInfosResult != null && batchUserInfosResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh batch get user info success\");\n        } else {\n            System.out.println(\"mesh batch get user info failure\");\n        }\n\n        //测试发送好友请求\n        IMResult<Void> sendFriendRequestResult = MeshAdmin.sendFriendRequest(\"user1\", \"user2\", \"hello\");\n        if (sendFriendRequestResult != null && (sendFriendRequestResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS || sendFriendRequestResult.getErrorCode() == ErrorCode.ERROR_CODE_ALREADY_FRIENDS)) {\n            System.out.println(\"mesh send friend request success\");\n        } else {\n            System.out.println(\"mesh send friend request failure\");\n        }\n\n        //测试处理好友请求\n        IMResult<Void> handleFriendRequestResult = MeshAdmin.handleFriendRequest(\"user2\", \"user1\", 1);\n        if (handleFriendRequestResult != null && handleFriendRequestResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh handle friend request success\");\n        } else {\n            System.out.println(\"mesh handle friend request failure\");\n        }\n\n        //测试创建域\n        String domainId = \"test_domain_\" + System.currentTimeMillis();\n        InputOutputDomainInfo domainInfo = new InputOutputDomainInfo();\n        domainInfo.setDomainId(domainId);\n        domainInfo.setName(\"Test Domain\");\n        IMResult<Void> createDomainResult = MeshAdmin.createDomain(domainInfo);\n        if (createDomainResult != null && createDomainResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh create domain success\");\n        } else {\n            System.out.println(\"mesh create domain failure\");\n        }\n\n        //测试获取域\n        IMResult<InputOutputDomainInfo> getDomainResult = MeshAdmin.getDomain(domainId);\n        if (getDomainResult != null && getDomainResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh get domain success\");\n        } else {\n            System.out.println(\"mesh get domain failure\");\n        }\n\n        //测试获取所有域\n        IMResult<InputOutputDomainInfoList> getAllDomainResult = MeshAdmin.getAllDomain();\n        if (getAllDomainResult != null && getAllDomainResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh get all domain success\");\n        } else {\n            System.out.println(\"mesh get all domain failure\");\n        }\n\n        //测试ping域\n        IMResult<PojoDomainPingResponse> pingDomainResult = MeshAdmin.pingDomain(domainId);\n        if (pingDomainResult != null && pingDomainResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh ping domain success\");\n        } else {\n            System.out.println(\"mesh ping domain failure\");\n        }\n\n        //测试删除域\n        IMResult<Void> deleteDomainResult = MeshAdmin.deleteDomain(domainId);\n        if (deleteDomainResult != null && deleteDomainResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh delete domain success\");\n        } else {\n            System.out.println(\"mesh delete domain failure\");\n        }\n\n        //测试同步群组\n        PojoGroupInfo meshGroupInfo = new PojoGroupInfo();\n        meshGroupInfo.setTarget_id(\"mesh_group_\" + System.currentTimeMillis());\n        meshGroupInfo.setName(\"Mesh Test Group\");\n        meshGroupInfo.setOwner(\"user1\");\n        meshGroupInfo.setType(2);\n        List<PojoGroupMember> meshMembers = new ArrayList<>();\n        PojoGroupMember meshMember = new PojoGroupMember();\n        meshMember.setMember_id(\"user1\");\n        meshMembers.add(meshMember);\n        IMResult<Void> syncGroupResult = MeshAdmin.syncGroup(meshGroupInfo, meshMembers);\n        if (syncGroupResult != null && syncGroupResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh sync group success\");\n        } else {\n            System.out.println(\"mesh sync group failure\");\n        }\n\n        //测试发送消息\n        Conversation meshConversation = new Conversation();\n        meshConversation.setTarget(\"user2\");\n        meshConversation.setType(ProtoConstants.ConversationType.ConversationType_Private);\n        MessagePayload meshPayload = new MessagePayload();\n        meshPayload.setType(1);\n        meshPayload.setSearchableContent(\"mesh test message\");\n        IMResult<SendMessageResult> meshSendMessageResult = MeshAdmin.sendMessage(\"user1\", meshConversation, meshPayload, null);\n        if (meshSendMessageResult != null && meshSendMessageResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh send message success\");\n        } else {\n            System.out.println(\"mesh send message failure\");\n        }\n\n        //测试发布消息\n        if (meshSendMessageResult != null && meshSendMessageResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            SendMessageData publishMessageData = new SendMessageData();\n            publishMessageData.setSender(\"user1\");\n            publishMessageData.setConv(meshConversation);\n            publishMessageData.setPayload(meshPayload);\n            IMResult<SendMessageResult> publishMessageResult = MeshAdmin.publishMessage(publishMessageData, Arrays.asList(\"user2\"), meshSendMessageResult.getResult().getMessageUid());\n            if (publishMessageResult != null && publishMessageResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n                System.out.println(\"mesh publish message success\");\n            } else {\n                System.out.println(\"mesh publish message failure\");\n            }\n        }\n\n        //测试添加加入群组请求\n        IMResult<Void> addJoinGroupRequestResult = MeshAdmin.addJoinGroupRequest(\"user2\", meshGroupInfo.getTarget_id(), Arrays.asList(\"user3\"), \"please add me\", null);\n        if (addJoinGroupRequestResult != null && addJoinGroupRequestResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh add join group request success\");\n        } else {\n            System.out.println(\"mesh add join group request failure\");\n        }\n\n        //测试会议用户请求\n        IMResult<PojoUserConferenceResponse> userConferenceRequestResult = MeshAdmin.userConferenceRequest(\"client1\", \"user1\", \"test_request\", 1, \"room1\", \"test_data\", false);\n        if (userConferenceRequestResult != null && userConferenceRequestResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh user conference request success\");\n        } else {\n            System.out.println(\"mesh user conference request failure\");\n        }\n\n        //测试会议用户事件\n        IMResult<Void> userConferenceEventResult = MeshAdmin.userConferenceEvent(\"test_event_data\", \"user1\", \"client1\", false);\n        if (userConferenceEventResult != null && userConferenceEventResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            System.out.println(\"mesh user conference event success\");\n        } else {\n            System.out.println(\"mesh user conference event failure\");\n        }\n\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/MeshAdmin.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.pojos.mesh.*;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\n\nimport java.util.List;\n\n/**\n * Mesh服务管理类\n * <p>\n * 提供Mesh网络（多域互联）服务管理相关的功能，包括：\n * <ul>\n * <li>域管理（创建、删除、查询）</li>\n * <li>跨域用户搜索</li>\n * <li>跨域好友管理</li>\n * <li>跨域消息发送</li>\n * <li>跨域群组管理</li>\n * <li>会议控制</li>\n * </ul>\n * </p>\n */\npublic class MeshAdmin {\n    /**\n     * 创建域\n     * @param domainInfo 域信息\n     * @return 创建结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> createDomain(InputOutputDomainInfo domainInfo) throws Exception {\n        String path = APIPath.Create_Domain;\n        return AdminHttpUtils.httpJsonPost(path, domainInfo, Void.class);\n    }\n\n    /**\n     * 获取域信息\n     * @param domainId 域ID\n     * @return 域信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<InputOutputDomainInfo> getDomain(String domainId) throws Exception {\n        String path = APIPath.Get_Domain;\n        InputStringValue inputId = new InputStringValue();\n        inputId.setValue(domainId);\n        return AdminHttpUtils.httpJsonPost(path, inputId, InputOutputDomainInfo.class);\n    }\n\n    /**\n     * 删除域\n     * @param domainId 域ID\n     * @return 删除结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> deleteDomain(String domainId) throws Exception {\n        String path = APIPath.Destroy_Domain;\n        InputStringValue inputId = new InputStringValue();\n        inputId.setValue(domainId);\n        return AdminHttpUtils.httpJsonPost(path, inputId, Void.class);\n    }\n\n    /**\n     * 获取所有域列表\n     * @return 域信息列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<InputOutputDomainInfoList> getAllDomain() throws Exception {\n        String path = APIPath.List_Domain;\n        return AdminHttpUtils.httpJsonPost(path, null, InputOutputDomainInfoList.class);\n    }\n\n    /**\n     * 批量获取用户信息\n     * @param userIds 用户ID列表\n     * @return 用户信息列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputUserInfoList> getBatchUserInfos(List<String> userIds) throws Exception {\n        String path = APIPath.User_Batch_Get_Infos;\n        OutputStringList getUserInfo = new OutputStringList(userIds);\n        return AdminHttpUtils.httpJsonPost(path, getUserInfo, OutputUserInfoList.class);\n    }\n\n    /**\n     * 搜索用户\n     * @param keyword 搜索关键词\n     * @param searchType 搜索类型\n     * @param userType 用户类型\n     * @param page 页码\n     * @return 搜索结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<PojoSearchUserRes> searchUser(String keyword, int searchType, int userType, int page) throws Exception {\n        String path = APIPath.Search_User;\n        PojoSearchUserReq req = new PojoSearchUserReq();\n        req.keyword = keyword;\n        req.searchType = searchType;\n        req.page = page;\n        req.userType = userType;\n        return AdminHttpUtils.httpJsonPost(path, req, PojoSearchUserRes.class);\n    }\n\n    /**\n     * 发送跨域好友请求\n     * @param userId 用户ID\n     * @param targetId 目标用户ID\n     * @param reason 申请理由\n     * @return 发送结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> sendFriendRequest(String userId, String targetId, String reason) throws Exception {\n        String path = APIPath.Friend_Send_Request;\n        InputAddFriendRequest input = new InputAddFriendRequest();\n        input.setUserId(userId);\n        input.setFriendUid(targetId);\n        input.setReason(reason);\n        input.setForce(false);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 处理跨域好友请求\n     * @param userId 用户ID\n     * @param targetId 目标用户ID\n     * @param status 状态\n     * @return 处理结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> handleFriendRequest(String userId, String targetId, int status) throws Exception {\n        String path = APIPath.Handle_Friend_Send_Request;\n        InputHandleFriendRequest input = new InputHandleFriendRequest();\n        input.setUserId(userId);\n        input.setFriendUid(targetId);\n        input.setStatus(status);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 发送跨域消息\n     * @param sender 发送者用户ID\n     * @param conversation 会话信息\n     * @param payload 消息内容\n     * @param toUsers 接收用户ID列表\n     * @return 发送结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<SendMessageResult> sendMessage(String sender, Conversation conversation, MessagePayload payload, List<String> toUsers) throws Exception {\n        String path = APIPath.Msg_Send;\n        SendMessageData messageData = new SendMessageData();\n        messageData.setSender(sender);\n        messageData.setConv(conversation);\n        messageData.setPayload(payload);\n        messageData.setToUsers(toUsers);\n        messageData.setMeshMessage(true);\n        if (payload.getType() == 1 && (payload.getSearchableContent() == null || payload.getSearchableContent().isEmpty())) {\n            System.out.println(\"Payload错误，Payload格式应该跟客户端消息encode出来的Payload对齐，这样客户端才能正确识别。比如文本消息，文本需要放到searchableContent属性。请与客户端同事确认Payload的格式，或则去 https://gitee.com/wfchat/android-chat/tree/master/client/src/main/java/cn/wildfirechat/message 找到消息encode的实现方法！\");\n        }\n        return AdminHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class);\n    }\n\n    /**\n     * 发布跨域消息\n     * @param messageData 消息数据\n     * @param receivers 接收者ID列表\n     * @param messageId 消息ID\n     * @return 发布结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<SendMessageResult> publishMessage(SendMessageData messageData, List<String> receivers, long messageId) throws Exception {\n        String path = APIPath.Msg_Publish;\n        PojoPublishMessageReq req = new PojoPublishMessageReq();\n        req.messageData = messageData;\n        req.receivers = receivers;\n        req.messageId = messageId;\n        return AdminHttpUtils.httpJsonPost(path, req, SendMessageResult.class);\n    }\n\n    /**\n     * 撤回跨域消息\n     * @param operator 操作者用户ID\n     * @param messageId 消息ID\n     * @return 撤回结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<String> recallMessage(String operator, long messageId) throws Exception {\n        String path = APIPath.Msg_Recall;\n        RecallMessageData req = new RecallMessageData();\n        req.setOperator(operator);\n        req.setMessageUid(messageId);\n        req.setUserRecall(true);\n        return AdminHttpUtils.httpJsonPost(path, req, String.class);\n    }\n\n    /**\n     * 更新跨域消息内容\n     * @param operator 操作者用户ID\n     * @param messageUid 消息UID\n     * @param payload 新的消息内容\n     * @param distribute 是否分发\n     * @return 更新结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> updateMessageContent(String operator, long messageUid, MessagePayload payload, boolean distribute) throws Exception {\n        String path = APIPath.Msg_Update;\n        UpdateMessageContentData updateMessageContentData = new UpdateMessageContentData();\n        updateMessageContentData.setOperator(operator);\n        updateMessageContentData.setMessageUid(messageUid);\n        updateMessageContentData.setPayload(payload);\n        updateMessageContentData.setDistribute(distribute?1:0);\n        updateMessageContentData.setUpdateTimestamp(0);\n        updateMessageContentData.setMeshLocal(1);\n        return AdminHttpUtils.httpJsonPost(path, updateMessageContentData, Void.class);\n    }\n\n    /**\n     * 同步跨域群组\n     * @param group_info 群组信息\n     * @param members 成员列表\n     * @return 同步结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> syncGroup(PojoGroupInfo group_info, List<PojoGroupMember> members) throws Exception {\n        String path = APIPath.Sync_Group;\n        PojoGroup pojoGroup = new PojoGroup();\n        pojoGroup.setGroup_info(group_info);\n        pojoGroup.setMembers(members);\n\n        return AdminHttpUtils.httpJsonPost(path, pojoGroup, Void.class);\n    }\n\n    /**\n     * 获取跨域群组信息\n     * @param groupId 群组ID\n     * @return 群组信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<PojoGroupInfo> getGroupInfo(String groupId) throws Exception {\n        return GroupAdmin.getGroupInfo(groupId);\n    }\n\n    /**\n     * 获取跨域群组成员列表\n     * @param groupId 群组ID\n     * @return 群组成员列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputGroupMemberList> getGroupMembers(String groupId) throws Exception {\n        return GroupAdmin.getGroupMembers(groupId);\n    }\n\n    /**\n     * 添加跨域群组成员\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param groupMembers 成员列表\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 添加结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> addGroupMembers(String operator, String groupId, List<PojoGroupMember> groupMembers, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Member_Add;\n        InputAddGroupMember addGroupMember = new InputAddGroupMember();\n        addGroupMember.setGroup_id(groupId);\n        addGroupMember.setMembers(groupMembers);\n        addGroupMember.setOperator(operator);\n        addGroupMember.setTo_lines(to_lines);\n        addGroupMember.setNotify_message(notify_message);\n        addGroupMember.setMeshMessage(true);\n        return AdminHttpUtils.httpJsonPost(path, addGroupMember, Void.class);\n    }\n\n    /**\n     * 添加跨域加群申请\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param userIds 用户ID列表\n     * @param reason 理由\n     * @param extra 额外信息\n     * @return 添加结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> addJoinGroupRequest(String operator, String groupId, List<String> userIds, String reason, String extra) throws Exception {\n        String path = APIPath.Group_Join_Request_Add;\n        PojoAddJoinGroupRequest addGroupMember = new PojoAddJoinGroupRequest();\n        addGroupMember.operator = operator;\n        addGroupMember.group_id = groupId;\n        addGroupMember.userIds = userIds;\n        addGroupMember.reason = reason;\n        addGroupMember.extra = extra;\n        return AdminHttpUtils.httpJsonPost(path, addGroupMember, Void.class);\n    }\n\n    /**\n     * 批量获取跨域群组信息\n     * @param groupIds 群组ID列表\n     * @return 群组信息列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<PojoGroupInfoList> batchGroupInfos(List<String> groupIds) throws Exception {\n        return GroupAdmin.batchGroupInfos(groupIds);\n    }\n\n    /**\n     * 退出跨域群组\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 退出结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> quitGroup(String operator, String groupId, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Member_Quit;\n        InputQuitGroup quitGroup = new InputQuitGroup();\n        quitGroup.setGroup_id(groupId);\n        quitGroup.setOperator(operator);\n        quitGroup.setTo_lines(to_lines);\n        quitGroup.setNotify_message(notify_message);\n        quitGroup.setMeshMessage(true);\n        return AdminHttpUtils.httpJsonPost(path, quitGroup, Void.class);\n    }\n\n    /**\n     * 解散跨域群组\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 解散结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> dismissGroup(String operator, String groupId, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Dismiss;\n        InputDismissGroup dismissGroup = new InputDismissGroup();\n        dismissGroup.setOperator(operator);\n        dismissGroup.setGroup_id(groupId);\n        dismissGroup.setTo_lines(to_lines);\n        dismissGroup.setNotify_message(notify_message);\n        dismissGroup.setMeshMessage(true);\n        return AdminHttpUtils.httpJsonPost(path, dismissGroup, Void.class);\n    }\n\n    /**\n     * 踢出跨域群组成员\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param groupMemberIds 成员用户ID列表\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 踢出结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> kickoffGroupMembers(String operator, String groupId, List<String> groupMemberIds, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Member_Kickoff;\n        InputKickoffGroupMember kickoffGroupMember = new InputKickoffGroupMember();\n        kickoffGroupMember.setGroup_id(groupId);\n        kickoffGroupMember.setMembers(groupMemberIds);\n        kickoffGroupMember.setOperator(operator);\n        kickoffGroupMember.setTo_lines(to_lines);\n        kickoffGroupMember.setMeshMessage(true);\n        kickoffGroupMember.setNotify_message(notify_message);\n        return AdminHttpUtils.httpJsonPost(path, kickoffGroupMember, Void.class);\n    }\n\n    /**\n     * 转让跨域群组\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param newOwner 新群主用户ID\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 转让结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> transferGroup(String operator, String groupId, String newOwner, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Transfer;\n        InputTransferGroup transferGroup = new InputTransferGroup();\n        transferGroup.setGroup_id(groupId);\n        transferGroup.setNew_owner(newOwner);\n        transferGroup.setOperator(operator);\n        transferGroup.setTo_lines(to_lines);\n        transferGroup.setNotify_message(notify_message);\n        transferGroup.setMeshMessage(true);\n        return AdminHttpUtils.httpJsonPost(path, transferGroup, Void.class);\n    }\n\n    /**\n     * 修改跨域群组信息\n     * @param operator 操作者用户ID\n     * @param groupId 群组ID\n     * @param type 修改信息类型（ModifyGroupInfoType）\n     * @param value 新值\n     * @param to_lines 消息同步到的线路列表\n     * @param notify_message 通知消息\n     * @return 修改结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> modifyGroupInfo(String operator, String groupId, /*ModifyGroupInfoType*/int type, String value, List<Integer> to_lines, MessagePayload  notify_message) throws Exception {\n        String path = APIPath.Group_Modify_Info;\n        InputModifyGroupInfo modifyGroupInfo = new InputModifyGroupInfo();\n        modifyGroupInfo.setGroup_id(groupId);\n        modifyGroupInfo.setOperator(operator);\n        modifyGroupInfo.setTo_lines(to_lines);\n        modifyGroupInfo.setType(type);\n        modifyGroupInfo.setValue(value);\n        modifyGroupInfo.setNotify_message(notify_message);\n        modifyGroupInfo.setMeshMessage(true);\n        return AdminHttpUtils.httpJsonPost(path, modifyGroupInfo, Void.class);\n    }\n\n    /**\n     * 用户会议请求\n     * @param clientID 客户端ID\n     * @param fromUser 发起用户ID\n     * @param request 请求内容\n     * @param sessionId 会话ID\n     * @param roomId 房间ID\n     * @param data 数据\n     * @param advanced 是否高级模式\n     * @return 会议响应\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<PojoUserConferenceResponse> userConferenceRequest(String clientID, String fromUser, String request, long sessionId, String roomId, String data, boolean advanced) throws Exception {\n        String path = APIPath.Conference_User_Request;\n        PojoUserConferenceRequest conferenceRequest = new PojoUserConferenceRequest();\n        conferenceRequest.clientID = clientID;\n        conferenceRequest.fromUser = fromUser;\n        conferenceRequest.request = request;\n        conferenceRequest.sessionId = sessionId;\n        conferenceRequest.roomId = roomId;\n        conferenceRequest.data = data;\n        conferenceRequest.advanced = advanced;\n        return AdminHttpUtils.httpJsonPost(path, conferenceRequest, PojoUserConferenceResponse.class);\n    }\n\n    /**\n     * 用户会议事件\n     * @param data 事件数据\n     * @param userId 用户ID\n     * @param clientId 客户端ID\n     * @param isRobot 是否为机器人\n     * @return 事件处理结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> userConferenceEvent(String data, String userId, String clientId, boolean isRobot) throws Exception {\n        String path = APIPath.Conference_User_Event;\n        PojoUserConferenceEvent event = new PojoUserConferenceEvent();\n        event.data = data;\n        event.userId = userId;\n        event.clientId = clientId;\n        event.isRobot = isRobot;\n        return AdminHttpUtils.httpJsonPost(path, event, Void.class);\n    }\n\n    /**\n     * Ping域\n     * @param domainId 域ID\n     * @return Ping响应\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<PojoDomainPingResponse> pingDomain(String domainId) throws Exception {\n        String path = APIPath.Ping_Domain;\n        PojoDomainPingRequest request = new PojoDomainPingRequest();\n        request.domainId = domainId;\n        return AdminHttpUtils.httpJsonPost(path, request, PojoDomainPingResponse.class);\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/MessageAdmin.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\n\nimport java.util.List;\n\n/**\n * 消息管理类\n * <p>\n * 提供消息管理相关的功能，包括：\n * <ul>\n * <li>发送消息（单聊、群聊、聊天室等）</li>\n * <li>撤回消息</li>\n * <li>删除消息</li>\n * <li>更新消息内容</li>\n * <li>广播和群发消息</li>\n * <li>会话管理</li>\n * <li>消息已读和投递状态查询</li>\n * </ul>\n * </p>\n */\npublic class MessageAdmin {\n    /**\n     * 发送消息\n     * @param sender 发送者用户ID\n     * @param conversation 会话信息\n     * @param payload 消息内容\n     * @return 发送结果，包含消息ID\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<SendMessageResult> sendMessage(String sender, Conversation conversation, MessagePayload payload) throws Exception {\n        return sendMessage(sender, conversation, payload, null);\n    }\n\n    /**\n     * 发送消息（可指定部分接收用户）\n     * <p>\n     * toUsers为发送给会话中部分用户用的，正常为null，仅当需要指定群/频道/聊天室中部分接收用户时使用\n     * </p>\n     * @param sender 发送者用户ID\n     * @param conversation 会话信息\n     * @param payload 消息内容\n     * @param toUsers 接收用户ID列表，null表示发送给会话中所有用户\n     * @return 发送结果，包含消息ID\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<SendMessageResult> sendMessage(String sender, Conversation conversation, MessagePayload payload, List<String> toUsers) throws Exception {\n        return sendMessage(sender, conversation, payload, toUsers, false);\n    }\n\n    /**\n     * 发送消息（完整参数版本）\n     * <p>\n     * toUsers为发送给会话中部分用户用的，正常为null，仅当需要指定群/频道/聊天室中部分接收用户时使用\n     * </p>\n     * @param sender 发送者用户ID\n     * @param conversation 会话信息\n     * @param payload 消息内容\n     * @param toUsers 接收用户ID列表，null表示发送给会话中所有用户\n     * @param isUserMessage 是否为用户消息\n     * @return 发送结果，包含消息ID\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<SendMessageResult> sendMessage(String sender, Conversation conversation, MessagePayload payload, List<String> toUsers, boolean isUserMessage) throws Exception {\n        String path = APIPath.Msg_Send;\n        SendMessageData messageData = new SendMessageData();\n        messageData.setSender(sender);\n        messageData.setConv(conversation);\n        messageData.setPayload(payload);\n        messageData.setToUsers(toUsers);\n        messageData.setUserMessage(isUserMessage);\n        if (payload.getType() == 1 && (payload.getSearchableContent() == null || payload.getSearchableContent().isEmpty())) {\n            System.out.println(\"Payload错误，Payload格式应该跟客户端消息encode出来的Payload对齐，这样客户端才能正确识别。比如文本消息，文本需要放到searchableContent属性。请与客户端同事确认Payload的格式，或则去 https://gitee.com/wfchat/android-chat/tree/master/client/src/main/java/cn/wildfirechat/message 找到消息encode的实现方法！\");\n        }\n        return AdminHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class);\n    }\n\n    /**\n     * 撤回消息\n     * @param operator 操作者用户ID\n     * @param messageUid 消息UID\n     * @return 撤回结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<String> recallMessage(String operator, long messageUid) throws Exception {\n        String path = APIPath.Msg_Recall;\n        RecallMessageData messageData = new RecallMessageData();\n        messageData.setOperator(operator);\n        messageData.setMessageUid(messageUid);\n        return AdminHttpUtils.httpJsonPost(path, messageData, String.class);\n    }\n\n    /**\n     * 删除消息（仅专业版支持）\n     * @param messageUid 消息UID\n     * @return 删除结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> deleteMessage(long messageUid) throws Exception {\n        String path = APIPath.Msg_Delete;\n        DeleteMessageData deleteMessageData = new DeleteMessageData();\n        deleteMessageData.setMessageUid(messageUid);\n        return AdminHttpUtils.httpJsonPost(path, deleteMessageData, Void.class);\n    }\n\n    /**\n     * 清除用户消息（仅专业版支持）\n     * @param userId 用户ID\n     * @param conversation 会话信息\n     * @param fromTime 起始时间\n     * @param toTime 结束时间\n     * @return 清除结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> clearUserMessages(String userId, Conversation conversation, long fromTime, long toTime) throws Exception {\n        String path = APIPath.Msg_Clear_By_User;\n        InputClearUserMessages clearUserMessages = new InputClearUserMessages(userId, conversation, fromTime, toTime);\n        return AdminHttpUtils.httpJsonPost(path, clearUserMessages, Void.class);\n    }\n\n    /**\n     * 更新消息内容（仅专业版支持）\n     * @param operator 操作者用户ID\n     * @param messageUid 消息UID\n     * @param payload 新的消息内容\n     * @param distribute 是否分发更新\n     * @return 更新结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> updateMessageContent(String operator, long messageUid, MessagePayload payload, boolean distribute) throws Exception {\n        String path = APIPath.Msg_Update;\n        UpdateMessageContentData updateMessageContentData = new UpdateMessageContentData();\n        updateMessageContentData.setOperator(operator);\n        updateMessageContentData.setMessageUid(messageUid);\n        updateMessageContentData.setPayload(payload);\n        updateMessageContentData.setDistribute(distribute?1:0);\n        updateMessageContentData.setUpdateTimestamp(0);\n        return AdminHttpUtils.httpJsonPost(path, updateMessageContentData, Void.class);\n    }\n\n    /**\n     * 清除会话（仅专业版支持）\n     * @param userId 用户ID\n     * @param conversation 会话信息\n     * @return 清除结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> clearConversation(String userId, Conversation conversation) throws Exception {\n        String path = APIPath.Conversation_Delete;\n        InputUserConversation input = new InputUserConversation();\n        input.userId = userId;\n        input.conversation = conversation;\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 获取单条消息\n     * <p>如果想要更多消息的读取，可以直接读取IM服务的数据库</p>\n     * @param messageUid 消息UID\n     * @return 消息数据\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputMessageData> getMessage(long messageUid) throws Exception {\n        String path = APIPath.Msg_GetOne;\n        InputMessageUid inputMessageUid = new InputMessageUid(messageUid);\n        return AdminHttpUtils.httpJsonPost(path, inputMessageUid, OutputMessageData.class);\n    }\n\n    /**\n     * 撤回广播消息（仅专业版支持）\n     * @param operator 操作者用户ID\n     * @param messageUid 消息UID\n     * @return 撤回结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> recallBroadCastMessage(String operator, long messageUid) throws Exception {\n        String path = APIPath.Msg_RecallBroadCast;\n        RecallMessageData messageData = new RecallMessageData();\n        messageData.setOperator(operator);\n        messageData.setMessageUid(messageUid);\n        return AdminHttpUtils.httpJsonPost(path, messageData, Void.class);\n    }\n\n    /**\n     * 撤回群发消息\n     * @param operator 操作者用户ID\n     * @param messageUid 消息UID\n     * @param receivers 接收者ID列表\n     * @return 撤回结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> recallMultiCastMessage(String operator, long messageUid, List<String> receivers) throws Exception {\n        String path = APIPath.Msg_RecallMultiCast;\n        RecallMultiCastMessageData messageData = new RecallMultiCastMessageData();\n        messageData.operator = operator;\n        messageData.messageUid = messageUid;\n        messageData.receivers = receivers;\n        return AdminHttpUtils.httpJsonPost(path, messageData, Void.class);\n    }\n\n    /**\n     * 删除广播消息（仅专业版支持）\n     * @param operator 操作者用户ID\n     * @param messageUid 消息UID\n     * @return 删除结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> deleteBroadCastMessage(String operator, long messageUid) throws Exception {\n        String path = APIPath.Msg_DeleteBroadCast;\n        RecallMessageData messageData = new RecallMessageData();\n        messageData.setOperator(operator);\n        messageData.setMessageUid(messageUid);\n        return AdminHttpUtils.httpJsonPost(path, messageData, Void.class);\n    }\n\n    /**\n     * 删除群发消息\n     * @param operator 操作者用户ID\n     * @param messageUid 消息UID\n     * @param receivers 接收者ID列表\n     * @return 删除结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> deleteMultiCastMessage(String operator, long messageUid, List<String> receivers) throws Exception {\n        String path = APIPath.Msg_DeleteMultiCast;\n        RecallMultiCastMessageData messageData = new RecallMultiCastMessageData();\n        messageData.operator = operator;\n        messageData.messageUid = messageUid;\n        messageData.receivers = receivers;\n        return AdminHttpUtils.httpJsonPost(path, messageData, Void.class);\n    }\n\n    /**\n     * 广播消息（仅专业版支持）\n     * @param sender 发送者用户ID\n     * @param line 线路\n     * @param payload 消息内容\n     * @return 广播结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<BroadMessageResult> broadcastMessage(String sender, int line, MessagePayload payload) throws Exception {\n        String path = APIPath.Msg_Broadcast;\n        BroadMessageData messageData = new BroadMessageData();\n        messageData.setSender(sender);\n        messageData.setLine(line);\n        messageData.setPayload(payload);\n        return AdminHttpUtils.httpJsonPost(path, messageData, BroadMessageResult.class);\n    }\n\n    /**\n     * 群发消息\n     * @param sender 发送者用户ID\n     * @param receivers 接收者ID列表\n     * @param line 线路\n     * @param payload 消息内容\n     * @return 群发结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<MultiMessageResult> multicastMessage(String sender, List<String> receivers, int line, MessagePayload payload) throws Exception {\n        String path = APIPath.Msg_Multicast;\n        MulticastMessageData messageData = new MulticastMessageData();\n        messageData.setSender(sender);\n        messageData.setTargets(receivers);\n        messageData.setLine(line);\n        messageData.setPayload(payload);\n        return AdminHttpUtils.httpJsonPost(path, messageData, MultiMessageResult.class);\n    }\n\n    /**\n     * 获取会话已读时间戳\n     * @param userId 用户ID\n     * @param conversation 会话信息\n     * @return 已读时间戳\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputTimestamp> getConversationReadTimestamp(String userId, Conversation conversation) throws Exception {\n        String path = APIPath.Msg_ConvRead;\n        InputGetConvReadTime input = new InputGetConvReadTime(userId, conversation.getType(), conversation.getTarget(), conversation.getLine());\n        return AdminHttpUtils.httpJsonPost(path, input, OutputTimestamp.class);\n    }\n\n    /**\n     * 获取消息投递时间戳\n     * @param userId 用户ID\n     * @return 投递时间戳\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputTimestamp> getMessageDelivery(String userId) throws Exception {\n        String path = APIPath.Msg_Delivery;\n        InputUserId input = new InputUserId(userId);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputTimestamp.class);\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/MomentsAdmin.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.pojos.moments.FeedPojo;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\n\n/**\n * 朋友圈管理类\n * <p>\n * 提供朋友圈（动态）管理相关的功能。\n * </p>\n */\npublic class MomentsAdmin {\n    /**\n     * 发布朋友圈动态\n     * @param feedPojo 动态内容\n     * @return 发布结果，包含消息ID\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<SendMessageResult> postFeeds(FeedPojo feedPojo) throws Exception {\n        String path = APIPath.Admin_Moments_Post_Feed;\n        return AdminHttpUtils.httpJsonPost(path, feedPojo, SendMessageResult.class);\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/RelationAdmin.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\n\n/**\n * 好友关系管理类\n * <p>\n * 提供好友关系管理相关的功能，包括：\n * <ul>\n * <li>设置和获取好友关系</li>\n * <li>黑名单管理</li>\n * <li>好友别名和额外信息管理</li>\n * <li>好友请求发送</li>\n * <li>关系查询</li>\n * </ul>\n * </p>\n */\npublic class RelationAdmin {\n    /**\n     * 设置用户好友关系\n     * @param userId 用户ID\n     * @param targetId 目标用户ID\n     * @param isFriend true-设置为好友，false-删除好友\n     * @param extra 额外信息\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setUserFriend(String userId, String targetId, boolean isFriend, String extra) throws Exception {\n        String path = APIPath.Friend_Update_Status;\n        InputUpdateFriendStatusRequest input = new InputUpdateFriendStatusRequest();\n        input.setUserId(userId);\n        input.setFriendUid(targetId);\n        input.setStatus(isFriend ? 0 : 1); //历史遗留问题，在IM数据库中0是好友，1是好友被删除。\n        input.setExtra(extra);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 获取好友列表\n     * @param userId 用户ID\n     * @return 好友ID列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputStringList> getFriendList(String userId) throws Exception {\n        String path = APIPath.Friend_Get_List;\n        InputUserId input = new InputUserId();\n        input.setUserId(userId);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputStringList.class);\n    }\n\n    /**\n     * 设置黑名单\n     * @param userId 用户ID\n     * @param targetId 目标用户ID\n     * @param isBlacklist true-加入黑名单，false-移出黑名单\n     * @return 设置结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> setUserBlacklist(String userId, String targetId, boolean isBlacklist) throws Exception {\n        String path = APIPath.Blacklist_Update_Status;\n        InputBlacklistRequest input = new InputBlacklistRequest();\n        input.setUserId(userId);\n        input.setTargetUid(targetId);\n        input.setStatus(isBlacklist ? 2 : 1);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 获取用户黑名单\n     * @param userId 用户ID\n     * @return 黑名单用户ID列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputStringList> getUserBlacklist(String userId) throws Exception {\n        String path = APIPath.Blacklist_Get_List;\n        InputUserId input = new InputUserId();\n        input.setUserId(userId);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputStringList.class);\n    }\n\n    /**\n     * 更新好友别名\n     * @param operator 操作者用户ID\n     * @param targetId 目标用户ID\n     * @param alias 别名\n     * @return 更新结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> updateFriendAlias(String operator, String targetId, String alias) throws Exception {\n        String path = APIPath.Friend_Set_Alias;\n        InputUpdateAlias input = new InputUpdateAlias();\n        input.setOperator(operator);\n        input.setTargetId(targetId);\n        input.setAlias(alias);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 获取好友别名\n     * @param operator 操作者用户ID\n     * @param targetId 目标用户ID\n     * @return 好友别名\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputGetAlias> getFriendAlias(String operator, String targetId) throws Exception {\n        String path = APIPath.Friend_Get_Alias;\n        InputGetAlias input = new InputGetAlias();\n        input.setOperator(operator);\n        input.setTargetId(targetId);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputGetAlias.class);\n    }\n\n    /**\n     * 更新好友额外信息\n     * @param operator 操作者用户ID\n     * @param targetId 目标用户ID\n     * @param extra 额外信息\n     * @return 更新结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> updateFriendExtra(String operator, String targetId, String extra) throws Exception {\n        String path = APIPath.Friend_Set_Extra;\n        InputUpdateFriendExtra input = new InputUpdateFriendExtra();\n        input.setOperator(operator);\n        input.setTargetId(targetId);\n        input.setExtra(extra);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 发送好友请求\n     * @param userId 用户ID\n     * @param targetId 目标用户ID\n     * @param reason 申请理由\n     * @param force 是否强制添加（直接成为好友无需对方同意）\n     * @return 发送结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> sendFriendRequest(String userId, String targetId, String reason, boolean force) throws Exception {\n        String path = APIPath.Friend_Send_Request;\n        InputAddFriendRequest input = new InputAddFriendRequest();\n        input.setUserId(userId);\n        input.setFriendUid(targetId);\n        input.setReason(reason);\n        input.setForce(force);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 获取两个用户之间的关系\n     * @param userId 用户1的ID\n     * @param targetId 用户2的ID\n     * @return 关系信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<RelationPojo> getRelation(String userId, String targetId) throws Exception {\n        String path = APIPath.Relation_Get;\n        StringPairPojo input = new StringPairPojo(userId, targetId);\n        return AdminHttpUtils.httpJsonPost(path, input, RelationPojo.class);\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/RobotService.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.pojos.moments.*;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.RobotHttpUtils;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.HttpStatus;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.client.methods.HttpPut;\nimport org.apache.http.entity.ContentType;\nimport org.apache.http.entity.FileEntity;\nimport org.apache.http.entity.InputStreamEntity;\nimport org.apache.http.entity.mime.MultipartEntityBuilder;\nimport org.apache.http.entity.mime.content.FileBody;\nimport org.apache.http.entity.mime.content.InputStreamBody;\nimport org.apache.http.util.EntityUtils;\n\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URLConnection;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.List;\n\nimport static cn.wildfirechat.proto.ProtoConstants.ApplicationType.ApplicationType_Robot;\n\n/**\n * 机器人服务类\n * <p>\n * 提供机器人相关的功能，包括：\n * <ul>\n * <li>发送和回复消息</li>\n * <li>获取用户信息</li>\n * <li>群组管理</li>\n * <li>朋友圈管理</li>\n * <li>会议控制</li>\n * <li>回调管理</li>\n * </ul>\n * </p>\n */\npublic class RobotService implements Closeable {\n    private final RobotHttpUtils robotHttpUtils;\n\n    /**\n     * 创建机器人服务实例\n     * @param url IM服务器地址\n     * @param robotId 机器人ID\n     * @param robotSecret 机器人密钥\n     */\n    public RobotService(String url, String robotId, String robotSecret) {\n        robotHttpUtils = new RobotHttpUtils(url, robotId, robotSecret);\n    }\n\n    /**\n     * 获取机器人ID\n     * @return 机器人ID\n     */\n    public String getRobotId() {\n        return robotHttpUtils.getRobotId();\n    }\n\n    /**\n     * 发送消息\n     * @param sender 发送者用户ID\n     * @param conversation 会话信息\n     * @param payload 消息内容\n     * @return 发送结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public IMResult<SendMessageResult> sendMessage(String sender, Conversation conversation, MessagePayload payload) throws Exception {\n        return sendMessage(sender, conversation, payload, null);\n    }\n\n    /**\n     * 发送消息（可指定接收用户）\n     * @param sender 发送者用户ID\n     * @param conversation 会话信息\n     * @param payload 消息内容\n     * @param toUsers 接收用户ID列表\n     * @return 发送结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public IMResult<SendMessageResult> sendMessage(String sender, Conversation conversation, MessagePayload payload, List<String> toUsers) throws Exception {\n        String path = APIPath.Robot_Message_Send;\n        SendMessageData messageData = new SendMessageData();\n        messageData.setSender(sender);\n        messageData.setConv(conversation);\n        messageData.setToUsers(toUsers);\n        messageData.setPayload(payload);\n        return robotHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class);\n    }\n\n    public IMResult<SendMessageResult> replyMessage(long messageUid, MessagePayload payload, boolean only2Sender) throws Exception {\n        String path = APIPath.Robot_Message_Reply;\n        ReplyMessageData messageData = new ReplyMessageData();\n        messageData.setMessageUid(messageUid);\n        messageData.setOnly2Sender(only2Sender);\n        messageData.setPayload(payload);\n        return robotHttpUtils.httpJsonPost(path, messageData, SendMessageResult.class);\n    }\n\n    public IMResult<String> recallMessage(long messageUid) throws Exception {\n        String path = APIPath.Robot_Message_Recall;\n        RecallMessageData messageData = new RecallMessageData();\n        messageData.setMessageUid(messageUid);\n        return robotHttpUtils.httpJsonPost(path, messageData, String.class);\n    }\n\n    public IMResult<Void> updateMessage(long messageUid, MessagePayload payload) throws Exception {\n        String path = APIPath.Robot_Message_Update;\n        UpdateMessageContentData updateMessageContentData = new UpdateMessageContentData();\n        updateMessageContentData.setMessageUid(messageUid);\n        updateMessageContentData.setPayload(payload);\n        updateMessageContentData.setUpdateTimestamp(0);\n        updateMessageContentData.setDistribute(1);\n        return robotHttpUtils.httpJsonPost(path, updateMessageContentData, Void.class);\n    }\n\n    public IMResult<InputOutputUserInfo> getUserInfo(String userId) throws Exception {\n        String path = APIPath.Robot_User_Info;\n        InputGetUserInfo getUserInfo = new InputGetUserInfo(userId, null, null);\n        return robotHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);\n    }\n\n    public IMResult<InputOutputUserInfo> getUserInfoByMobile(String phone) throws Exception {\n        String path = APIPath.Robot_User_Info;\n        InputGetUserInfo getUserInfo = new InputGetUserInfo(null, null, phone);\n        return robotHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);\n    }\n\n    public IMResult<InputOutputUserInfo> getUserInfoByName(String userName) throws Exception {\n        String path = APIPath.Robot_User_Info;\n        InputGetUserInfo getUserInfo = new InputGetUserInfo(null, userName, null);\n        return robotHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);\n    }\n\n    public IMResult<Void> setCallback(String url) throws Exception {\n        String path = APIPath.Robot_Set_Callback;\n        RobotCallbackPojo pojo = new RobotCallbackPojo();\n        pojo.setUrl(url);\n        return robotHttpUtils.httpJsonPost(path, pojo, Void.class);\n    }\n    \n    public IMResult<RobotCallbackPojo> getCallback() throws Exception {\n        String path = APIPath.Robot_Get_Callback;\n        return robotHttpUtils.httpJsonPost(path, null, RobotCallbackPojo.class);\n    }\n\n    public IMResult<Void> deleteCallback() throws Exception {\n        String path = APIPath.Robot_Delete_Callback;\n        return robotHttpUtils.httpJsonPost(path, null, Void.class);\n    }\n\n    public IMResult<OutputRobot> getProfile() throws Exception {\n        String path = APIPath.Robot_Get_Profile;\n        return robotHttpUtils.httpJsonPost(path, null, OutputRobot.class);\n    }\n\n    /*\n    type可选范围为MyInfoType，注意不能修改电话号码，如果要修改电话号码请使用adminapi进行修改\n     */\n    public IMResult<Void> updateProfile(int/*MyInfoType*/ type, String value) throws Exception {\n        String path = APIPath.Robot_Update_Profile;\n        IntStringPairPojo pojo = new IntStringPairPojo(type, value);\n        return robotHttpUtils.httpJsonPost(path, pojo, Void.class);\n    }\n\n    public IMResult<OutputCreateGroupResult> createGroup(PojoGroupInfo group_info, List<PojoGroupMember> members, String member_extra, List<Integer> to_lines, MessagePayload notify_message) throws Exception {\n        String path = APIPath.Robot_Create_Group;\n        PojoGroup pojoGroup = new PojoGroup();\n        pojoGroup.setGroup_info(group_info);\n        pojoGroup.setMembers(members);\n        InputCreateGroup createGroup = new InputCreateGroup();\n        createGroup.setGroup(pojoGroup);\n        createGroup.setMember_extra(member_extra);\n        createGroup.setTo_lines(to_lines);\n        createGroup.setNotify_message(notify_message);\n\n        return robotHttpUtils.httpJsonPost(path, createGroup, OutputCreateGroupResult.class);\n    }\n\n    public IMResult<PojoGroupInfo> getGroupInfo(String groupId) throws Exception {\n        String path = APIPath.Robot_Group_Get_Info;\n        InputGetGroup input = new InputGetGroup();\n        input.setGroupId(groupId);\n\n        return robotHttpUtils.httpJsonPost(path, input, PojoGroupInfo.class);\n    }\n\n    public IMResult<Void> dismissGroup(String groupId, List<Integer> to_lines, MessagePayload notify_message) throws Exception {\n        String path = APIPath.Robot_Group_Dismiss;\n        InputDismissGroup dismissGroup = new InputDismissGroup();\n        dismissGroup.setGroup_id(groupId);\n        dismissGroup.setTo_lines(to_lines);\n        dismissGroup.setNotify_message(notify_message);\n        return robotHttpUtils.httpJsonPost(path, dismissGroup, Void.class);\n    }\n\n    public IMResult<Void> transferGroup(String groupId, String newOwner, List<Integer> to_lines, MessagePayload notify_message) throws Exception {\n        String path = APIPath.Robot_Group_Transfer;\n        InputTransferGroup transferGroup = new InputTransferGroup();\n        transferGroup.setGroup_id(groupId);\n        transferGroup.setNew_owner(newOwner);\n        transferGroup.setTo_lines(to_lines);\n        transferGroup.setNotify_message(notify_message);\n        return robotHttpUtils.httpJsonPost(path, transferGroup, Void.class);\n    }\n\n    public IMResult<Void> modifyGroupInfo(String groupId, /*ModifyGroupInfoType*/int type, String value, List<Integer> to_lines, MessagePayload notify_message) throws Exception {\n        String path = APIPath.Robot_Group_Modify_Info;\n        InputModifyGroupInfo modifyGroupInfo = new InputModifyGroupInfo();\n        modifyGroupInfo.setGroup_id(groupId);\n        modifyGroupInfo.setTo_lines(to_lines);\n        modifyGroupInfo.setType(type);\n        modifyGroupInfo.setValue(value);\n        modifyGroupInfo.setNotify_message(notify_message);\n        return robotHttpUtils.httpJsonPost(path, modifyGroupInfo, Void.class);\n    }\n\n\n    public IMResult<OutputGroupMemberList> getGroupMembers(String groupId) throws Exception {\n        String path = APIPath.Robot_Group_Member_List;\n        InputGetGroup input = new InputGetGroup();\n        input.setGroupId(groupId);\n        return robotHttpUtils.httpJsonPost(path, input, OutputGroupMemberList.class);\n    }\n\n    public IMResult<PojoGroupMember> getGroupMember(String groupId, String memberId) throws Exception {\n        String path = APIPath.Robot_Group_Member_Get;\n        InputGetGroupMember input = new InputGetGroupMember();\n        input.setGroupId(groupId);\n        input.setMemberId(memberId);\n        return robotHttpUtils.httpJsonPost(path, input, PojoGroupMember.class);\n    }\n\n    public IMResult<Void> addGroupMembers(String groupId, List<PojoGroupMember> groupMembers, String member_extra, List<Integer> to_lines, MessagePayload notify_message) throws Exception {\n        String path = APIPath.Robot_Group_Member_Add;\n        InputAddGroupMember addGroupMember = new InputAddGroupMember();\n        addGroupMember.setGroup_id(groupId);\n        addGroupMember.setMembers(groupMembers);\n        addGroupMember.setMemberExtra(member_extra);\n        addGroupMember.setTo_lines(to_lines);\n        addGroupMember.setNotify_message(notify_message);\n        return robotHttpUtils.httpJsonPost(path, addGroupMember, Void.class);\n    }\n\n    public IMResult<Void> setGroupManager(String groupId, List<String> groupMemberIds, boolean isManager, List<Integer> to_lines, MessagePayload notify_message) throws Exception {\n        String path = APIPath.Robot_Group_Set_Manager;\n        InputSetGroupManager addGroupMember = new InputSetGroupManager();\n        addGroupMember.setGroup_id(groupId);\n        addGroupMember.setMembers(groupMemberIds);\n        addGroupMember.setIs_manager(isManager);\n        addGroupMember.setTo_lines(to_lines);\n        addGroupMember.setNotify_message(notify_message);\n        return robotHttpUtils.httpJsonPost(path, addGroupMember, Void.class);\n    }\n\n    public IMResult<Void> muteGroupMember(String groupId, List<String> groupMemberIds, boolean isMute, List<Integer> to_lines, MessagePayload notify_message) throws Exception {\n        String path = APIPath.Robot_Group_Mute_Member;\n        InputMuteGroupMember addGroupMember = new InputMuteGroupMember();\n        addGroupMember.setGroup_id(groupId);\n        addGroupMember.setMembers(groupMemberIds);\n        addGroupMember.setIs_manager(isMute);\n        addGroupMember.setTo_lines(to_lines);\n        addGroupMember.setNotify_message(notify_message);\n        return robotHttpUtils.httpJsonPost(path, addGroupMember, Void.class);\n    }\n\n    public IMResult<Void> allowGroupMember(String groupId, List<String> groupMemberIds, boolean isAllow, List<Integer> to_lines, MessagePayload notify_message) throws Exception {\n        String path = APIPath.Robot_Group_Allow_Member;\n        InputMuteGroupMember addGroupMember = new InputMuteGroupMember();\n        addGroupMember.setGroup_id(groupId);\n        addGroupMember.setMembers(groupMemberIds);\n        addGroupMember.setIs_manager(isAllow);\n        addGroupMember.setTo_lines(to_lines);\n        addGroupMember.setNotify_message(notify_message);\n        return robotHttpUtils.httpJsonPost(path, addGroupMember, Void.class);\n    }\n\n    public IMResult<Void> kickoffGroupMembers(String groupId, List<String> groupMemberIds, List<Integer> to_lines, MessagePayload notify_message) throws Exception {\n        String path = APIPath.Robot_Group_Member_Kickoff;\n        InputKickoffGroupMember kickoffGroupMember = new InputKickoffGroupMember();\n        kickoffGroupMember.setGroup_id(groupId);\n        kickoffGroupMember.setMembers(groupMemberIds);\n        kickoffGroupMember.setTo_lines(to_lines);\n        kickoffGroupMember.setNotify_message(notify_message);\n        return robotHttpUtils.httpJsonPost(path, kickoffGroupMember, Void.class);\n    }\n\n    public IMResult<Void> quitGroup(String groupId, List<Integer> to_lines, MessagePayload notify_message) throws Exception {\n        String path = APIPath.Robot_Group_Member_Quit;\n        InputQuitGroup quitGroup = new InputQuitGroup();\n        quitGroup.setGroup_id(groupId);\n        quitGroup.setTo_lines(to_lines);\n        quitGroup.setNotify_message(notify_message);\n        return robotHttpUtils.httpJsonPost(path, quitGroup, Void.class);\n    }\n\n    public IMResult<Void> setGroupMemberAlias(String groupId, String memberId, String alias, List<Integer> to_lines, MessagePayload notify_message) throws Exception {\n        String path = APIPath.Robot_Group_Set_Member_Alias;\n        InputSetGroupMemberAlias input = new InputSetGroupMemberAlias();\n        input.setGroup_id(groupId);\n        input.setMemberId(memberId);\n        input.setAlias(alias);\n        input.setTo_lines(to_lines);\n        input.setNotify_message(notify_message);\n        return robotHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    public IMResult<Void> setGroupMemberExtra(String groupId, String memberId, String extra, List<Integer> to_lines, MessagePayload notify_message) throws Exception {\n        String path = APIPath.Robot_Group_Set_Member_Extra;\n        InputSetGroupMemberExtra input = new InputSetGroupMemberExtra();\n        input.setGroup_id(groupId);\n        input.setMemberId(memberId);\n        input.setExtra(extra);\n        input.setTo_lines(to_lines);\n        input.setNotify_message(notify_message);\n        return robotHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    public IMResult<OutputApplicationUserInfo> applicationGetUserInfo(String authCode) throws Exception {\n        String path = APIPath.Robot_Application_Get_UserInfo;\n        InputApplicationGetUserInfo input = new InputApplicationGetUserInfo();\n        input.setAuthCode(authCode);\n        return robotHttpUtils.httpJsonPost(path, input, OutputApplicationUserInfo.class);\n    }\n\n    public OutputApplicationConfigData getApplicationSignature() {\n        int nonce = (int)(Math.random() * 100000 + 3);\n        long timestamp = System.currentTimeMillis()/1000;\n        String str = nonce + \"|\" + robotHttpUtils.getRobotId() + \"|\" + timestamp + \"|\" + robotHttpUtils.getRobotSecret();\n        String sign = DigestUtils.sha1Hex(str);\n        OutputApplicationConfigData configData = new OutputApplicationConfigData();\n        configData.setAppId(robotHttpUtils.getRobotId());\n        configData.setAppType(ApplicationType_Robot);\n        configData.setTimestamp(timestamp);\n        configData.setNonceStr(nonce+\"\");\n        configData.setSignature(sign);\n        return configData;\n    }\n\n    public IMResult<String> sendConferenceRequest(String robotId, String clientId, String request, long sessionId, String roomId, String data, boolean advance) throws Exception {\n        String path = APIPath.Robot_Conference_Request;\n        InputConferenceRequest input = new InputConferenceRequest(robotId, clientId, request, sessionId, roomId, data, advance);\n        return robotHttpUtils.httpJsonPost(path, input, String.class);\n    }\n\n    public IMResult<FeedPojo> postMomentsFeed(int/*MomentsContentType*/ type, String text, List<MediaEntry> medias, List<String> toUsers, List<String> excludeUsers, List<String> mentionedUsers, String extra) throws Exception {\n        String path = APIPath.Robot_Moments_Post_Feed;\n        FeedPojo feedPojo = new FeedPojo();\n        feedPojo.type = type;\n        feedPojo.text = text;\n        feedPojo.medias = medias;\n        feedPojo.to = toUsers;\n        feedPojo.ex = excludeUsers;\n        feedPojo.mu = mentionedUsers;\n        feedPojo.extra = extra;\n        IMResult<PostFeedResult> imResult = robotHttpUtils.httpJsonPost(path, feedPojo, PostFeedResult.class);\n        IMResult<FeedPojo> feedResult = new IMResult<>();\n        if(imResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            feedPojo.feedId = imResult.result.id;\n            feedPojo.timestamp = imResult.result.timestamp;\n            feedResult.setCode(ErrorCode.ERROR_CODE_SUCCESS.getCode());\n            feedResult.setResult(feedPojo);\n        } else {\n            feedResult.setCode(imResult.getCode());\n            feedResult.setMsg(imResult.getMsg());\n        }\n        return feedResult;\n    }\n\n    public IMResult<Void> updateMomentsFeed(long feedId, int/*MomentsContentType*/ type, String text, List<MediaEntry> medias, List<String> toUsers, List<String> excludeUsers, List<String> mentionedUsers, String extra) throws Exception {\n        String path = APIPath.Robot_Moments_Update_Feed;\n        FeedPojo feedPojo = new FeedPojo();\n        feedPojo.feedId = feedId;\n        feedPojo.type = type;\n        feedPojo.text = text;\n        feedPojo.medias = medias;\n        feedPojo.to = toUsers;\n        feedPojo.ex = excludeUsers;\n        feedPojo.mu = mentionedUsers;\n        feedPojo.extra = extra;\n        return robotHttpUtils.httpJsonPost(path, feedPojo, Void.class);\n    }\n\n    public IMResult<FeedsPojo> getMomentsFeeds(long feedId, int count, String user) throws Exception {\n        String path = APIPath.Robot_Moments_Pull_Feeds;\n        PullFeedRequestPojo requestPojo = new PullFeedRequestPojo();\n        requestPojo.feedId = feedId;\n        requestPojo.count = count;\n        requestPojo.user = user;\n        return robotHttpUtils.httpJsonPost(path, requestPojo, FeedsPojo.class);\n    }\n\n    public IMResult<FeedPojo> getMomentsFeed(long feedId) throws Exception {\n        String path = APIPath.Robot_Moments_Fetch_Feed;\n        PullOneFeedRequestPojo requestPojo = new PullOneFeedRequestPojo();\n        requestPojo.feedId = feedId;\n        return robotHttpUtils.httpJsonPost(path, requestPojo, FeedPojo.class);\n    }\n\n    public IMResult<Void> deleteMomentsFeed(long feedId) throws Exception {\n        String path = APIPath.Robot_Moments_Recall_Feed;\n        IdPojo requestPojo = new IdPojo();\n        requestPojo.id = feedId;\n        return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);\n    }\n\n    public IMResult<CommentPojo> postMomentsComment(long feedId, long replyId, int/*MomentsCommentType*/ type, String text, String replyTo, String extra) throws Exception {\n        String path = APIPath.Robot_Moments_Post_Comment;\n        CommentPojo commentPojo = new CommentPojo();\n        commentPojo.type = type;\n        commentPojo.text = text;\n        commentPojo.replyId = replyId;\n        commentPojo.feedId = feedId;\n        commentPojo.replyTo = replyTo;\n        commentPojo.extra = extra;\n        IMResult<PostFeedResult> imResult = robotHttpUtils.httpJsonPost(path, commentPojo, PostFeedResult.class);\n        IMResult<CommentPojo> feedResult = new IMResult<>();\n        if(imResult.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {\n            commentPojo.commentId = imResult.result.id;\n            commentPojo.timestamp = imResult.result.timestamp;\n            feedResult.setCode(ErrorCode.ERROR_CODE_SUCCESS.getCode());\n            feedResult.setResult(commentPojo);\n        } else {\n            feedResult.setCode(imResult.getCode());\n            feedResult.setMsg(imResult.getMsg());\n        }\n        return feedResult;\n    }\n\n    public IMResult<Void> deleteMomentsComment(long feedId, long commentId) throws Exception {\n        String path = APIPath.Robot_Moments_Recall_Comment;\n        IdPojo requestPojo = new IdPojo();\n        requestPojo.id = commentId;\n        requestPojo.id2 = feedId;\n        return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);\n    }\n\n    public IMResult<MomentProfilePojo> getUserMomentsProfile(String userId) throws Exception {\n        String path = APIPath.Robot_Moments_Fetch_Profiles;\n        PullProfileRequestPojo requestPojo = new PullProfileRequestPojo();\n        requestPojo.u = userId;\n        return robotHttpUtils.httpJsonPost(path, requestPojo, MomentProfilePojo.class);\n    }\n\n    public IMResult<Void> updateMomentsBackgroundUrl(String url) throws Exception {\n        String path = APIPath.Robot_Moments_Update_Profiles_Value;\n        PushProfileValueRequestPojo requestPojo = new PushProfileValueRequestPojo();\n        requestPojo.t = 0;\n        requestPojo.v = url;\n        return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);\n    }\n\n    public IMResult<Void> updateMomentsStrangerVisibleCount(int count) throws Exception {\n        String path = APIPath.Robot_Moments_Update_Profiles_Value;\n        PushProfileValueRequestPojo requestPojo = new PushProfileValueRequestPojo();\n        requestPojo.t = 1;\n        requestPojo.i = count;\n        return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);\n    }\n\n    public IMResult<Void> updateMomentsVisibleScope(int/*MomentsVisibleScope*/ scope) throws Exception {\n        String path = APIPath.Robot_Moments_Update_Profiles_Value;\n        PushProfileValueRequestPojo requestPojo = new PushProfileValueRequestPojo();\n        requestPojo.t = 2;\n        requestPojo.i = scope;\n        return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);\n    }\n\n    public IMResult<Void> updateMomentsBlackList(List<String> addList, List<String> removeList) throws Exception {\n        String path = APIPath.Robot_Moments_Update_Profiles_List_Value;\n        PushProfileListRequestPojo requestPojo = new PushProfileListRequestPojo();\n        requestPojo.b = false;\n        requestPojo.al = addList;\n        requestPojo.rl = removeList;\n        return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);\n    }\n\n    public IMResult<Void> updateMomentsBlockList(List<String> addList, List<String> removeList) throws Exception {\n        String path = APIPath.Robot_Moments_Update_Profiles_List_Value;\n        PushProfileListRequestPojo requestPojo = new PushProfileListRequestPojo();\n        requestPojo.b = true;\n        requestPojo.al = addList;\n        requestPojo.rl = removeList;\n        return robotHttpUtils.httpJsonPost(path, requestPojo, Void.class);\n    }\n\n    public IMResult<OutputPresignedUploadUrl> getPresignedUploadUrl(String fileName, int/*ProtoConstants.MessageMediaType*/ mediaType, String contentType) throws Exception {\n        String path = APIPath.Robot_Get_Presigned_Upload_Url;\n\n        InputGetPresignedUploadUrl requestPojo = new InputGetPresignedUploadUrl();\n        requestPojo.fileName = fileName;\n        requestPojo.mediaType = mediaType;\n        requestPojo.contentType = contentType;\n        return robotHttpUtils.httpJsonPost(path, requestPojo, OutputPresignedUploadUrl.class);\n    }\n\n    /**\n     * 根据文件名获取Content-Type\n     *\n     * @param fileName 文件名\n     * @return Content-Type，如果无法识别则返回 \"application/octet-stream\"\n     */\n    private String getContentTypeByFileName(String fileName) {\n        if (fileName == null || fileName.isEmpty()) {\n            return \"application/octet-stream\";\n        }\n        \n        // 首先尝试使用 URLConnection 猜测\n        String contentType = URLConnection.guessContentTypeFromName(fileName);\n        \n        // 如果无法识别，使用常见扩展名映射\n        if (contentType == null) {\n            String lowerName = fileName.toLowerCase();\n            if (lowerName.endsWith(\".jpg\") || lowerName.endsWith(\".jpeg\")) {\n                contentType = \"image/jpeg\";\n            } else if (lowerName.endsWith(\".png\")) {\n                contentType = \"image/png\";\n            } else if (lowerName.endsWith(\".gif\")) {\n                contentType = \"image/gif\";\n            } else if (lowerName.endsWith(\".bmp\")) {\n                contentType = \"image/bmp\";\n            } else if (lowerName.endsWith(\".webp\")) {\n                contentType = \"image/webp\";\n            } else if (lowerName.endsWith(\".mp4\")) {\n                contentType = \"video/mp4\";\n            } else if (lowerName.endsWith(\".mov\")) {\n                contentType = \"video/quicktime\";\n            } else if (lowerName.endsWith(\".avi\")) {\n                contentType = \"video/x-msvideo\";\n            } else if (lowerName.endsWith(\".mp3\")) {\n                contentType = \"audio/mpeg\";\n            } else if (lowerName.endsWith(\".wav\")) {\n                contentType = \"audio/wav\";\n            } else if (lowerName.endsWith(\".pdf\")) {\n                contentType = \"application/pdf\";\n            } else if (lowerName.endsWith(\".doc\")) {\n                contentType = \"application/msword\";\n            } else if (lowerName.endsWith(\".docx\")) {\n                contentType = \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\";\n            } else if (lowerName.endsWith(\".xls\")) {\n                contentType = \"application/vnd.ms-excel\";\n            } else if (lowerName.endsWith(\".xlsx\")) {\n                contentType = \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\";\n            } else if (lowerName.endsWith(\".ppt\")) {\n                contentType = \"application/vnd.ms-powerpoint\";\n            } else if (lowerName.endsWith(\".pptx\")) {\n                contentType = \"application/vnd.openxmlformats-officedocument.presentationml.presentation\";\n            } else if (lowerName.endsWith(\".txt\")) {\n                contentType = \"text/plain\";\n            } else if (lowerName.endsWith(\".html\") || lowerName.endsWith(\".htm\")) {\n                contentType = \"text/html\";\n            } else if (lowerName.endsWith(\".json\")) {\n                contentType = \"application/json\";\n            } else if (lowerName.endsWith(\".xml\")) {\n                contentType = \"application/xml\";\n            } else if (lowerName.endsWith(\".zip\")) {\n                contentType = \"application/zip\";\n            } else if (lowerName.endsWith(\".rar\")) {\n                contentType = \"application/x-rar-compressed\";\n            } else if (lowerName.endsWith(\".7z\")) {\n                contentType = \"application/x-7z-compressed\";\n            } else if (lowerName.endsWith(\".tar\")) {\n                contentType = \"application/x-tar\";\n            } else if (lowerName.endsWith(\".gz\")) {\n                contentType = \"application/gzip\";\n            } else {\n                contentType = \"application/octet-stream\";\n            }\n        }\n        \n        return contentType;\n    }\n\n\n    /**\n     * 上传文件\n     * <p>\n     * 流程：先调用getPresignedUploadUrl获取预签名上传地址，然后直接上传文件。\n     * 上传成功后返回文件的下载地址等信息。\n     * </p>\n     *\n     * @param file        要上传的文件\n     * @return 上传结果，包含下载地址\n     * @throws Exception 上传失败时抛出异常\n     */\n    public IMResult<String> uploadFile(File file) throws Exception {\n        return uploadFile(file, ProtoConstants.MessageMediaType.FILE, null);\n    }\n    /**\n     * 上传文件\n     * <p>\n     * 流程：先调用getPresignedUploadUrl获取预签名上传地址，然后直接上传文件。\n     * 上传成功后返回文件的下载地址等信息。\n     * </p>\n     *\n     * @param file        要上传的文件\n     * @param mediaType   媒体类型，参考{@link cn.wildfirechat.proto.ProtoConstants.MessageMediaType}\n     * @param contentType 文件Content-Type，例如 \"image/jpeg\", \"application/octet-stream\" 等；\n     *                    如果为null或空，则根据文件名自动识别\n     * @return 上传结果，包含下载地址\n     * @throws Exception 上传失败时抛出异常\n     */\n    public IMResult<String> uploadFile(File file, int mediaType, String contentType) throws Exception {\n        if (file == null || !file.exists()) {\n            throw new IllegalArgumentException(\"文件不能为空或不存在\");\n        }\n\n        // 如果未指定Content-Type，根据文件名自动获取\n        if (contentType == null || contentType.isEmpty()) {\n            contentType = getContentTypeByFileName(file.getName());\n        }\n\n        return doUploadFile(file.getName(), mediaType, contentType, file, null);\n    }\n\n    /**\n     * 执行文件上传的公共方法\n     * <p>\n     * 根据服务器类型选择不同的上传方式：\n     * <ul>\n     * <li>type = 1（七牛云）：使用 POST + multipart/form-data 表单上传</li>\n     * <li>type = 其他（阿里云、Minio等）：使用 PUT + 二进制流上传</li>\n     * </ul>\n     * </p>\n     *\n     * @param fileName    文件名\n     * @param mediaType   媒体类型\n     * @param contentType Content-Type\n     * @param file        文件对象（用于七牛云上传）\n     * @param inputStream 输入流（用于其他类型上传，可为null）\n     * @return 上传结果\n     * @throws Exception 上传失败时抛出异常\n     */\n    private IMResult<String> doUploadFile(String fileName, int mediaType,\n                                                             String contentType,\n                                                             File file,\n                                                             InputStream inputStream) throws Exception {\n        // 1. 获取预签名上传地址\n        IMResult<OutputPresignedUploadUrl> presignedResult = getPresignedUploadUrl(\n                fileName, mediaType, contentType);\n\n        if (presignedResult.getErrorCode() != ErrorCode.ERROR_CODE_SUCCESS) {\n            IMResult<String> imResult = new IMResult<>();\n            imResult.setCode(presignedResult.code);\n            imResult.setMsg(presignedResult.msg);\n            return imResult;\n        }\n\n        OutputPresignedUploadUrl presignedUrl = presignedResult.getResult();\n        if (presignedUrl == null || presignedUrl.uploadUrl == null) {\n            throw new Exception(\"预签名上传地址为空\");\n        }\n\n        // 2. 根据服务器类型选择上传方式\n        if (presignedUrl.type == 1) {\n            // 七牛云：使用 POST + multipart/form-data 表单上传\n            return uploadToQiniu(presignedUrl, file, inputStream, fileName, contentType);\n        } else {\n            // 其他（阿里云、Minio、腾讯云、华为云、AWS S3等）：使用 PUT 上传\n            return uploadToOther(presignedUrl, file, inputStream, contentType);\n        }\n    }\n\n    /**\n     * 上传到七牛云（type = 1）\n     * 使用 POST + multipart/form-data 表单格式\n     */\n    private IMResult<String> uploadToQiniu(OutputPresignedUploadUrl presignedUrl, File file,\n                                            InputStream inputStream, String fileName, \n                                            String contentType) throws Exception {\n        // 解析七牛云上传地址：格式为 \"https://host?token?key\"\n        String uploadUrl = presignedUrl.uploadUrl;\n        String token;\n        String key;\n        \n        int tokenStart = uploadUrl.indexOf('?');\n        int keyStart = uploadUrl.indexOf('?', tokenStart + 1);\n        \n        if (tokenStart == -1 || keyStart == -1) {\n            throw new Exception(\"七牛云上传地址格式错误\");\n        }\n        \n        String baseUrl = uploadUrl.substring(0, tokenStart);\n        token = uploadUrl.substring(tokenStart + 1, keyStart);\n        key = uploadUrl.substring(keyStart + 1);\n\n        HttpPost httpPost = new HttpPost(baseUrl);\n        try {\n            MultipartEntityBuilder builder = MultipartEntityBuilder.create();\n            \n            // 添加 token 和 key 字段\n            builder.addTextBody(\"token\", token);\n            builder.addTextBody(\"key\", key);\n            \n            // 添加文件字段\n            if (file != null) {\n                builder.addPart(\"file\", new FileBody(file, ContentType.create(contentType), fileName));\n            } else if (inputStream != null) {\n                builder.addPart(\"file\", new InputStreamBody(inputStream, ContentType.create(contentType), fileName));\n            }\n            \n            httpPost.setEntity(builder.build());\n\n            HttpResponse response = robotHttpUtils.getHttpClient().execute(httpPost);\n            int statusCode = response.getStatusLine().getStatusCode();\n            \n            // 消耗响应体\n            if (response.getEntity() != null) {\n                EntityUtils.consumeQuietly(response.getEntity());\n            }\n\n            // 七牛云返回 200 表示成功\n            if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_CREATED) {\n                throw new Exception(\"文件上传到七牛云失败，HTTP状态码：\" + statusCode);\n            }\n\n            IMResult<String> imResult = new IMResult<>();\n            imResult.setCode(0);\n            imResult.setResult(presignedUrl.downloadUrl);\n            return imResult;\n        } finally {\n            httpPost.releaseConnection();\n        }\n    }\n\n    /**\n     * 上传到其他对象存储（type != 1）\n     * 使用 PUT + 二进制流\n     */\n    private IMResult<String> uploadToOther(OutputPresignedUploadUrl presignedUrl, File file,\n                                            InputStream inputStream, String contentType) throws Exception {\n        HttpPut httpPut = new HttpPut(presignedUrl.uploadUrl);\n        try {\n            // 设置请求实体\n            if (file != null) {\n                FileEntity fileEntity = new FileEntity(file);\n                fileEntity.setContentType(contentType);\n                httpPut.setEntity(fileEntity);\n            } else if (inputStream != null) {\n                InputStreamEntity streamEntity = new InputStreamEntity(inputStream);\n                streamEntity.setContentType(contentType);\n                httpPut.setEntity(streamEntity);\n            }\n\n            HttpResponse response = robotHttpUtils.getHttpClient().execute(httpPut);\n            int statusCode = response.getStatusLine().getStatusCode();\n            \n            // 消耗响应体，确保连接可以被复用\n            if (response.getEntity() != null) {\n                EntityUtils.consumeQuietly(response.getEntity());\n            }\n\n            if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_CREATED) {\n                throw new Exception(\"文件上传失败，HTTP状态码：\" + statusCode);\n            }\n\n            IMResult<String> imResult = new IMResult<>();\n            imResult.setCode(0);\n            imResult.setResult(presignedUrl.downloadUrl);\n            return imResult;\n        } finally {\n            httpPut.releaseConnection();\n        }\n    }\n\n    /**\n     * 上传文件（通过输入流）\n     * <p>\n     * 流程：先调用getPresignedUploadUrl获取预签名上传地址，然后直接上传文件。\n     * 上传成功后返回文件的下载地址等信息。\n     * </p>\n     *\n     * @param inputStream 文件输入流\n     * @param fileName    文件名\n     * @return 上传结果，包含下载地址\n     * @throws Exception 上传失败时抛出异常\n     */\n    public IMResult<String> uploadFile(InputStream inputStream, String fileName) throws Exception {\n        return uploadFile(inputStream, fileName, ProtoConstants.MessageMediaType.FILE, null);\n    }\n    /**\n     * 上传文件（通过输入流）\n     * <p>\n     * 流程：先调用getPresignedUploadUrl获取预签名上传地址，然后直接上传文件。\n     * 上传成功后返回文件的下载地址等信息。\n     * </p>\n     * <p>\n     * <b>注意：</b>无论上传成功还是失败，此方法都会关闭输入流。\n     * </p>\n     *\n     * @param inputStream 文件输入流（此方法会关闭该流）\n     * @param fileName    文件名\n     * @param mediaType   媒体类型，参考{@link cn.wildfirechat.proto.ProtoConstants.MessageMediaType}\n     * @param contentType 文件Content-Type，例如 \"image/jpeg\", \"application/octet-stream\" 等；\n     *                    如果为null或空，则根据文件名自动识别\n     * @return 上传结果，包含下载地址\n     * @throws Exception 上传失败时抛出异常\n     */\n    public IMResult<String> uploadFile(InputStream inputStream, String fileName,\n                                                          int mediaType, String contentType) throws Exception {\n        if (inputStream == null) {\n            throw new IllegalArgumentException(\"输入流不能为空\");\n        }\n\n        // 如果未指定Content-Type，根据文件名自动获取\n        if (contentType == null || contentType.isEmpty()) {\n            contentType = getContentTypeByFileName(fileName);\n        }\n\n        return doUploadFile(fileName, mediaType, contentType, null, inputStream);\n        // 注意：正常流程下的流关闭在 uploadToQiniu 或 uploadToOther 的 finally 块中处理\n    }\n\n    @Override\n    public void close() throws IOException {\n        robotHttpUtils.close();\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/SensitiveAdmin.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\n\nimport java.util.List;\n\n/**\n * 敏感词管理类\n * <p>\n * 提供敏感词管理相关的功能，包括：\n * <ul>\n * <li>添加敏感词</li>\n * <li>删除敏感词</li>\n * <li>查询敏感词列表</li>\n * </ul>\n * </p>\n */\npublic class SensitiveAdmin {\n    /**\n     * 添加敏感词\n     * @param sensitives 敏感词列表\n     * @return 添加结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> addSensitives(List<String> sensitives) throws Exception {\n        String path = APIPath.Sensitive_Add;\n        InputOutputSensitiveWords input = new InputOutputSensitiveWords();\n        input.setWords(sensitives);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 删除敏感词\n     * @param sensitives 敏感词列表\n     * @return 删除结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> removeSensitives(List<String> sensitives) throws Exception {\n        String path = APIPath.Sensitive_Del;\n        InputOutputSensitiveWords input = new InputOutputSensitiveWords();\n        input.setWords(sensitives);\n        return AdminHttpUtils.httpJsonPost(path, input, Void.class);\n    }\n\n    /**\n     * 获取敏感词列表\n     * @return 敏感词列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<InputOutputSensitiveWords> getSensitives() throws Exception {\n        String path = APIPath.Sensitive_Query;\n        return AdminHttpUtils.httpJsonPost(path, null, InputOutputSensitiveWords.class);\n    }\n\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/UserAdmin.java",
    "content": "package cn.wildfirechat.sdk;\n\nimport cn.wildfirechat.common.APIPath;\nimport cn.wildfirechat.pojos.*;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport cn.wildfirechat.sdk.utilities.AdminHttpUtils;\n\nimport java.util.List;\n\n/**\n * 用户管理类\n * <p>\n * 提供用户管理相关的功能，包括：\n * <ul>\n * <li>用户信息的获取、创建、更新、销毁</li>\n * <li>机器人管理</li>\n * <li>用户封禁状态管理</li>\n * <li>用户在线状态查询</li>\n * <li>用户设备管理</li>\n * <li>用户Token管理</li>\n * </ul>\n * </p>\n */\npublic class UserAdmin {\n    /**\n     * 根据用户名获取用户信息（不包含已删除用户）\n     * @param name 用户名\n     * @return 用户信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<InputOutputUserInfo> getUserByName(String name) throws Exception {\n        return getUserByName(name, false);\n    }\n\n    /**\n     * 根据用户名获取用户信息\n     * @param name 用户名\n     * @param includeDeleted 是否包含已删除的用户\n     * @return 用户信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<InputOutputUserInfo> getUserByName(String name, boolean includeDeleted) throws Exception {\n        String path = APIPath.User_Get_Info;\n        InputGetUserInfo getUserInfo = new InputGetUserInfo(null, name, null, includeDeleted);\n        return AdminHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);\n    }\n\n    /**\n     * 根据用户ID获取用户信息（不包含已删除用户）\n     * @param userId 用户ID\n     * @return 用户信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<InputOutputUserInfo> getUserByUserId(String userId) throws Exception {\n        return getUserByUserId(userId, false);\n    }\n\n    /**\n     * 根据用户ID获取用户信息\n     * @param userId 用户ID\n     * @param includeDeleted 是否包含已删除的用户\n     * @return 用户信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<InputOutputUserInfo> getUserByUserId(String userId, boolean includeDeleted) throws Exception {\n        String path = APIPath.User_Get_Info;\n        InputGetUserInfo getUserInfo = new InputGetUserInfo(userId, null, null, includeDeleted);\n        return AdminHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);\n    }\n\n    /**\n     * 根据手机号获取用户信息（不包含已删除用户）\n     * @param mobile 手机号\n     * @return 用户信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<InputOutputUserInfo> getUserByMobile(String mobile) throws Exception {\n        return getUserByMobile(mobile, false);\n    }\n\n    /**\n     * 根据手机号获取用户信息\n     * @param mobile 手机号\n     * @param includeDeleted 是否包含已删除的用户\n     * @return 用户信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<InputOutputUserInfo> getUserByMobile(String mobile, boolean includeDeleted) throws Exception {\n        String path = APIPath.User_Get_Info;\n        InputGetUserInfo getUserInfo = new InputGetUserInfo(null, null, mobile, includeDeleted);\n        return AdminHttpUtils.httpJsonPost(path, getUserInfo, InputOutputUserInfo.class);\n    }\n\n    /**\n     * 根据邮箱获取用户信息列表\n     * @param email 邮箱地址\n     * @return 用户信息列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputUserInfoList> getUserByEmail(String email) throws Exception {\n        String path = APIPath.User_Get_Email_Info;\n        return AdminHttpUtils.httpJsonPost(path, email, OutputUserInfoList.class);\n    }\n\n    /**\n     * 获取所有用户列表（分页）\n     * @param count 每页数量\n     * @param offset 偏移量\n     * @return 用户列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputGetUserList> getAllUsers(int count, int offset) throws Exception {\n        String path = APIPath.User_Get_All;\n        InputGetUserList input = new InputGetUserList();\n        input.count = count;\n        input.offset = offset;\n        return AdminHttpUtils.httpJsonPost(path, input, OutputGetUserList.class);\n    }\n\n    /**\n     * 批量获取用户信息\n     * @param userIds 用户ID列表\n     * @return 用户信息列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputUserInfoList> getBatchUsers(List<String> userIds) throws Exception {\n        String path = APIPath.User_Batch_Get_Infos;\n        InputStringList input = new InputStringList();\n        input.setList(userIds);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputUserInfoList.class);\n    }\n\n    /**\n     * 创建用户\n     * @param user 用户信息\n     * @return 创建结果，包含用户ID\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputCreateUser> createUser(InputOutputUserInfo user) throws Exception {\n        String path = APIPath.Create_User;\n        return AdminHttpUtils.httpJsonPost(path, user, OutputCreateUser.class);\n    }\n\n    /**\n     * 更新用户信息\n     * @param user 用户信息\n     * @param flag 更新标志位，指定要更新的字段（UpdateUserInfoMask）\n     * @return 更新结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> updateUserInfo(InputOutputUserInfo user, int/*UpdateUserInfoMask*/ flag) throws Exception {\n        String path = APIPath.Update_User;\n        InputUpdateUserInfo updateUserInfo = new InputUpdateUserInfo();\n        updateUserInfo.flag = flag;\n        updateUserInfo.userInfo = user;\n        return AdminHttpUtils.httpJsonPost(path, updateUserInfo, Void.class);\n    }\n\n    /**\n     * 创建机器人\n     * @param robot 机器人信息\n     * @return 创建结果，包含机器人ID和Token\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputCreateRobot> createRobot(InputCreateRobot robot) throws Exception {\n        String path = APIPath.Create_Robot;\n        return AdminHttpUtils.httpJsonPost(path, robot, OutputCreateRobot.class);\n    }\n\n    /**\n     * 销毁机器人\n     * <p>销毁机器人和销毁用户使用同一个接口</p>\n     * @param userId 机器人用户ID\n     * @return 销毁结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> destroyRobot(String userId) throws Exception {\n        String path = APIPath.Destroy_User;\n        InputDestroyUser inputDestroyUser = new InputDestroyUser();\n        inputDestroyUser.setUserId(userId);\n        return AdminHttpUtils.httpJsonPost(path, inputDestroyUser, Void.class);\n    }\n\n    /**\n     * 获取机器人信息\n     * @param robotId 机器人ID\n     * @return 机器人信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputRobot> getRobotInfo(String robotId) throws Exception {\n        String path = APIPath.User_Get_Robot_Info;\n        InputRobotId getRobotInfo = new InputRobotId();\n        getRobotInfo.setRobotId(robotId);\n        return AdminHttpUtils.httpJsonPost(path, getRobotInfo, OutputRobot.class);\n    }\n\n    /**\n     * 获取用户的机器人列表\n     * @param userId 用户ID\n     * @return 机器人ID列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputStringList> getUserRobots(String userId) throws Exception {\n        String path = APIPath.User_Get_User_Robots;\n        InputUserId getRobotInfo = new InputUserId();\n        getRobotInfo.setUserId(userId);\n        return AdminHttpUtils.httpJsonPost(path, getRobotInfo, OutputStringList.class);\n    }\n\n    /**\n     * 获取用户的IM Token\n     * @param userId 用户ID\n     * @param clientId 客户端ID\n     * @param platform 平台类型\n     * @return Token信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputGetIMTokenData> getUserToken(String userId, String clientId, int platform) throws Exception {\n        String path = APIPath.User_Get_Token;\n        InputGetToken getToken = new InputGetToken(userId, clientId, platform);\n        return AdminHttpUtils.httpJsonPost(path, getToken, OutputGetIMTokenData.class);\n    }\n\n    /**\n     * 更新用户封禁状态\n     * @param userId 用户ID\n     * @param block 封禁状态：0-正常，1-封禁\n     * @return 更新结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> updateUserBlockStatus(String userId, int block) throws Exception {\n        String path = APIPath.User_Update_Block_Status;\n        InputOutputUserBlockStatus blockStatus = new InputOutputUserBlockStatus(userId, block);\n        return AdminHttpUtils.httpJsonPost(path, blockStatus, Void.class);\n    }\n\n    /**\n     * 检查用户封禁状态\n     * @param userId 用户ID\n     * @return 用户封禁状态\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputUserStatus> checkUserBlockStatus(String userId) throws Exception {\n        String path = APIPath.User_Check_Block_Status;\n        InputGetUserInfo getUserInfo = new InputGetUserInfo(userId, null, null);\n        return AdminHttpUtils.httpJsonPost(path, getUserInfo, OutputUserStatus.class);\n    }\n\n    /**\n     * 获取被封禁用户列表\n     * @return 被封禁用户列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputUserBlockStatusList> getBlockedList() throws Exception {\n        String path = APIPath.User_Get_Blocked_List;\n        return AdminHttpUtils.httpJsonPost(path, null, OutputUserBlockStatusList.class);\n    }\n\n    /**\n     * 检查用户在线状态\n     * @param userId 用户ID\n     * @return 用户在线状态\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputCheckUserOnline> checkUserOnlineStatus(String userId) throws Exception {\n        String path = APIPath.User_Get_Online_Status;\n        InputGetUserInfo getUserInfo = new InputGetUserInfo(userId, null, null);\n        return AdminHttpUtils.httpJsonPost(path, getUserInfo, OutputCheckUserOnline.class);\n    }\n\n    /**\n     * 强迫用户下线\n     * <p>\n     * 强迫用户下线后，用户需要重新获取token才能进行连接。\n     * userId必须有效，clientId可以为空。\n     * 当clientId为空时，踢下线所有客户端；当不为空时仅踢掉对应客户端。\n     * </p>\n     * @param userId 用户ID\n     * @param clientId 客户端ID，为空时踢下线所有客户端\n     * @return 下线结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> kickoffUserClient(String userId, String clientId) throws Exception {\n        String path = APIPath.User_Kickoff_Client;\n        StringPairPojo pojo = new StringPairPojo(userId, clientId);\n        return AdminHttpUtils.httpJsonPost(path, pojo, Void.class);\n    }\n\n    /**\n     * 销毁用户\n     * @param userId 用户ID\n     * @return 销毁结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<Void> destroyUser(String userId) throws Exception {\n        String path = APIPath.Destroy_User;\n        InputDestroyUser inputDestroyUser = new InputDestroyUser();\n        inputDestroyUser.setUserId(userId);\n        return AdminHttpUtils.httpJsonPost(path, inputDestroyUser, Void.class);\n    }\n\n    /**\n     * 创建或更新设备信息（仅专业版支持）\n     * @param device 设备信息\n     * @return 创建或更新结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputCreateDevice> createOrUpdateDevice(InputCreateDevice device) throws Exception {\n        String path = APIPath.CreateOrUpdate_Device;\n        return AdminHttpUtils.httpJsonPost(path, device, OutputCreateDevice.class);\n    }\n\n    /**\n     * 获取设备信息（仅专业版支持）\n     * @param deviceId 设备ID\n     * @return 设备信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputDevice> getDevice(String deviceId) throws Exception {\n        String path = APIPath.Get_Device;\n        InputDeviceId inputDeviceId = new InputDeviceId();\n        inputDeviceId.setDeviceId(deviceId);\n        return AdminHttpUtils.httpJsonPost(path, inputDeviceId, OutputDevice.class);\n    }\n\n    /**\n     * 获取用户的设备列表\n     * @param userId 用户ID\n     * @return 用户设备列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputDeviceList> getUserDevices(String userId) throws Exception {\n        String path = APIPath.Get_User_Devices;\n        InputUserId inputUserId = new InputUserId();\n        inputUserId.setUserId(userId);\n        return AdminHttpUtils.httpJsonPost(path, inputUserId, OutputDeviceList.class);\n    }\n\n    /**\n     * 获取在线用户数量\n     * @return 在线用户数量统计结果\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<GetOnlineUserCountResult> getOnlineUserCount() throws Exception {\n        return AdminHttpUtils.httpJsonPost(APIPath.User_Online_Count, null, GetOnlineUserCountResult.class);\n    }\n\n    /**\n     * 获取在线用户列表（分页）\n     * @param nodeId 节点ID，用于分布式部署场景\n     * @param offset 偏移量\n     * @param count 每页数量\n     * @return 在线用户列表\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<GetOnlineUserResult> getOnlineUser(int nodeId, int offset, int count) throws Exception {\n        GetOnlineUserRequest request = new GetOnlineUserRequest();\n        request.nodeId = nodeId;\n        request.offset = offset;\n        request.count = count;\n        return AdminHttpUtils.httpJsonPost(APIPath.User_Online_List, request, GetOnlineUserResult.class);\n    }\n\n    /**\n     * 通过应用授权码获取用户信息\n     * @param authCode 应用授权码\n     * @return 用户信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<OutputApplicationUserInfo> applicationGetUserInfo(String authCode) throws Exception {\n        String path = APIPath.User_Application_Get_UserInfo;\n        InputApplicationGetUserInfo input = new InputApplicationGetUserInfo();\n        input.setAuthCode(authCode);\n        return AdminHttpUtils.httpJsonPost(path, input, OutputApplicationUserInfo.class);\n    }\n\n    /**\n     * 获取用户会话信息\n     * @param userId 用户ID\n     * @return 用户会话信息\n     * @throws Exception 请求失败时抛出异常\n     */\n    public static IMResult<GetUserSessionResult> getUserSession(String userId) throws Exception {\n        InputUserId inputUserId = new InputUserId(userId);\n        return AdminHttpUtils.httpJsonPost(APIPath.User_Session_List, inputUserId, GetUserSessionResult.class);\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/ArticlesMessageContent.java",
    "content": "/*\n * Copyright (c) 2022 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\nimport org.json.simple.parser.JSONParser;\nimport org.json.simple.parser.ParseException;\n\nimport java.util.ArrayList;\nimport java.util.Base64;\nimport java.util.List;\n\n\n/**\n * 图文消息内容类\n * <p>\n * 表示图文链接类型的消息内容，包含一个主文章和多个子文章。\n * 通常用于公众号文章分享等场景。\n * </p>\n */\npublic class ArticlesMessageContent extends MessageContent {\n    public Article topArticle;\n    public ArrayList<Article> subArticles;\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Articles;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setSearchableContent(topArticle.title);\n        JSONObject object = new JSONObject();\n\n        object.put(\"top\", topArticle.toJson());\n        if (subArticles != null) {\n            JSONArray jsonArray = new JSONArray();\n            object.put(\"subArticles\", jsonArray);\n            for (Article article : subArticles) {\n                jsonArray.add(article.toJson());\n            }\n        }\n        payload.setBase64edData(Base64.getEncoder().encodeToString(object.toString().getBytes()));\n\n\n        return payload;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        try {\n            super.decode(payload);\n            JSONObject object = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));\n            JSONObject topObj = (JSONObject) object.get(\"top\");\n            this.topArticle = Article.fromJson(topObj);\n            JSONArray jsonArray = (JSONArray) object.get(\"subArticles\");\n            if (jsonArray != null && jsonArray.size() > 0) {\n                this.subArticles = new ArrayList<>();\n                for (int i = 0; i < jsonArray.size(); i++) {\n                    subArticles.add(Article.fromJson((JSONObject) jsonArray.get(i)));\n                }\n            }\n        } catch (ParseException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n\n    public List<LinkMessageContent> toLinkMessageContent() {\n        List<LinkMessageContent> contents = new ArrayList<>();\n        contents.add(this.topArticle.toLinkMessageContent());\n        if (this.subArticles != null) {\n            for (Article article : subArticles) {\n                contents.add(article.toLinkMessageContent());\n            }\n        }\n        return contents;\n    }\n\n    public static class Article {\n        public String articleId;\n        public String cover;\n        public String title;\n        public String digest;\n        public String url;\n        boolean readReport;\n\n        JSONObject toJson() {\n            JSONObject obj = new JSONObject();\n            obj.put(\"id\", articleId);\n            obj.put(\"cover\", cover);\n            obj.put(\"title\", title);\n            obj.put(\"digest\", digest);\n            obj.put(\"url\", url);\n            obj.put(\"rr\", readReport);\n\n\n            return obj;\n        }\n\n        static Article fromJson(JSONObject obj) {\n            Article article = new Article();\n            article.articleId = (String) obj.get(\"id\");\n            article.cover = (String) obj.get(\"cover\");\n            article.title = (String) obj.get(\"title\");\n            article.digest = (String) obj.get(\"digest\");\n            article.url = (String) obj.get(\"url\");\n            article.readReport = (boolean) obj.get(\"rr\");\n            return article;\n        }\n\n        public LinkMessageContent toLinkMessageContent() {\n            LinkMessageContent content = new LinkMessageContent(this.title, this.url);\n            content.setContentDigest(this.digest);\n            content.setThumbnailUrl(this.cover);\n            return content;\n        }\n\n        public Article() {\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/CallStartMessageContent.java",
    "content": "/*\n * Copyright (c) 2020 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport io.netty.util.internal.StringUtil;\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\nimport org.json.simple.parser.JSONParser;\nimport org.json.simple.parser.ParseException;\n\nimport java.util.ArrayList;\nimport java.util.Base64;\nimport java.util.List;\n\n/**\n * Created by heavyrain lee on 2017/12/6.\n */\n\n/**\n * 音视频通话消息内容类\n * <p>\n * 表示音视频通话相关的消息内容，包含通话ID、参与者、连接时间等信息。\n * 支持一对一和多人音视频通话。\n * </p>\n */\npublic class CallStartMessageContent extends MessageContent {\n    private String callId;\n    // 多人视音频是有效，不包含自己，一对一忽略此参数\n    private List<String> targetIds;\n    private long connectTime;\n    private long endTime;\n    private boolean audioOnly;\n    private String pin;\n\n\n    /**\n     * 0, UnKnown,\n     * 1, Busy,\n     * 2, SignalError,\n     * 3, Hangup,\n     * 4, MediaError,\n     * 5, RemoteHangup,\n     * 6, OpenCameraFailure,\n     * 7, Timeout,\n     * 8, AcceptByOtherClient\n     */\n    private int status;\n\n    /**\n     * 0，未知；1，多人版音视频；2，高级版音视频\n     */\n    private int type;\n\n    public CallStartMessageContent() {\n    }\n\n    public CallStartMessageContent(String callId, List<String> targetIds, boolean audioOnly) {\n        this.callId = callId;\n        this.audioOnly = audioOnly;\n        this.targetIds = targetIds;\n    }\n\n    public String getCallId() {\n        return callId;\n    }\n\n    public void setCallId(String callId) {\n        this.callId = callId;\n    }\n\n    public long getConnectTime() {\n        return connectTime;\n    }\n\n    public void setConnectTime(long connectTime) {\n        this.connectTime = connectTime;\n    }\n\n    public long getEndTime() {\n        return endTime;\n    }\n\n    public void setEndTime(long endTime) {\n        this.endTime = endTime;\n    }\n\n    public int getStatus() {\n        return status;\n    }\n\n    public void setStatus(int status) {\n        this.status = status;\n    }\n\n    public boolean isAudioOnly() {\n        return audioOnly;\n    }\n\n    public void setAudioOnly(boolean audioOnly) {\n        this.audioOnly = audioOnly;\n    }\n\n    public List<String> getTargetIds() {\n        return targetIds;\n    }\n\n    public void setTargetIds(List<String> targetIds) {\n        this.targetIds = targetIds;\n    }\n\n    public String getPin() {\n        return pin;\n    }\n\n    public void setPin(String pin) {\n        this.pin = pin;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Call_Start;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setContent(callId);\n        payload.setPushContent(\"音视频通话邀请\");\n\n            JSONObject objWrite = new JSONObject();\n            if (connectTime > 0) {\n                objWrite.put(\"c\", connectTime);\n            }\n\n            if (endTime > 0) {\n                objWrite.put(\"e\", endTime);\n            }\n\n            if (status > 0) {\n                objWrite.put(\"s\", status);\n            }\n\n            objWrite.put(\"t\", targetIds.get(0));\n            JSONArray ts = new JSONArray();\n            ts.addAll(targetIds);\n            objWrite.put(\"ts\", ts);\n            objWrite.put(\"a\", audioOnly ? 1 : 0);\n            objWrite.put(\"p\", pin);\n            if (this.type > 0) {\n                objWrite.put(\"ty\", this.type);\n            }\n\n            payload.setBase64edData(Base64.getEncoder().encodeToString(objWrite.toString().getBytes()));\n\n            JSONObject pushDataWrite = new JSONObject();\n            pushDataWrite.put(\"callId\", callId);\n            pushDataWrite.put(\"audioOnly\", audioOnly);\n            if (targetIds != null && targetIds.size() > 0) {\n                pushDataWrite.put(\"participants\", targetIds);\n            }\n            payload.setPushData(pushDataWrite.toString());\n        return payload;\n    }\n\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        callId = payload.getContent();\n\n        try {\n            if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {\n                JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));\n                connectTime = (long) jsonObject.get(\"c\");\n                endTime = (long) jsonObject.get(\"e\");\n                status = (int) jsonObject.get(\"s\");\n                pin = (String) jsonObject.get(\"p\");\n                type = (int) jsonObject.get(\"ty\");\n                JSONArray array = (JSONArray) jsonObject.get(\"ts\");\n                targetIds = new ArrayList<>();\n                if (array == null) {\n                    targetIds.add((String) jsonObject.get(\"t\"));\n                } else {\n                    for (int i = 0; i < array.size(); i++) {\n                        if (array.get(i) instanceof String) {\n                            targetIds.add((String) array.get(i));\n                        }\n                    }\n                }\n                audioOnly = (int)jsonObject.get(\"a\") > 0;\n            }\n        } catch (ParseException e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/CardMessageContent.java",
    "content": "/*\n * Copyright (c) 2020 WildFireChat. All rights reserved.\n */\n\n/*\n * Copyright (c) 2020 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport io.netty.util.internal.StringUtil;\nimport org.json.simple.JSONObject;\nimport org.json.simple.parser.JSONParser;\nimport org.json.simple.parser.ParseException;\n\nimport java.util.Base64;\n\n/**\n * 名片消息内容类\n * <p>\n * 表示分享的名片消息，可以是用户名片、群组名片、聊天室名片或频道名片。\n * </p>\n */\npublic class CardMessageContent extends MessageContent {\n    /**\n     * 0，用户；1，群组；2，聊天室；3，频道\n     */\n    private int type;\n    private String target;\n    // 用户名，一般是type为用户时使用\n    private String name;\n    private String displayName;\n    private String portrait;\n    private String from;\n\n    public CardMessageContent() {\n    }\n\n    public CardMessageContent(int type, String target, String displayName, String portrait, String from) {\n        this.type = type;\n        this.target = target;\n        this.displayName = displayName;\n        this.portrait = portrait;\n        this.from = from;\n    }\n\n    public String getTarget() {\n        return target;\n    }\n\n    public void setTarget(String target) {\n        this.target = target;\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 String getDisplayName() {\n        return displayName;\n    }\n\n    public void setDisplayName(String displayName) {\n        this.displayName = displayName;\n    }\n\n    public String getPortrait() {\n        return portrait;\n    }\n\n    public void setPortrait(String portrait) {\n        this.portrait = portrait;\n    }\n\n    public int getType() {\n        return type;\n    }\n\n    public void setType(int type) {\n        this.type = type;\n    }\n\n    public String getFrom() {\n        return from;\n    }\n\n    public void setFrom(String from) {\n        this.from = from;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Name_Card;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setContent(target);\n            JSONObject objWrite = new JSONObject();\n            objWrite.put(\"t\", type);\n            objWrite.put(\"n\", name);\n            objWrite.put(\"d\", displayName);\n            objWrite.put(\"p\", portrait);\n            objWrite.put(\"f\", from);\n\n            payload.setBase64edData(Base64.getEncoder().encodeToString(objWrite.toString().getBytes()));\n        return payload;\n    }\n\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        target = payload.getContent();\n        try {\n            if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {\n                JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));\n                type = (int) jsonObject.get(\"t\");\n                name = (String) jsonObject.get(\"n\");\n                displayName = (String) jsonObject.get(\"d\");\n                portrait = (String) jsonObject.get(\"p\");\n                from = (String) jsonObject.get(\"f\");\n            }\n        } catch (ParseException e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/DeleteMessageContent.java",
    "content": "package cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\n\n/**\n * 删除消息内容类\n * <p>\n * 表示消息删除通知，包含被删除消息的ID和操作者信息。\n * </p>\n */\npublic class DeleteMessageContent extends MessageContent {\n    private long messageId;\n    private String operatorId;\n\n    //必须有个空的构造函数\n    public DeleteMessageContent() {\n    }\n\n    public long getMessageId() {\n        return messageId;\n    }\n\n    public String getOperatorId() {\n        return operatorId;\n    }\n\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Delete;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Not_Persist;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        throw new RuntimeException(\"Delete message cannot encode\");\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        operatorId = payload.getContent();\n        messageId = Long.parseLong(new String(Base64.getDecoder().decode(payload.getBase64edData()), StandardCharsets.UTF_8));\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/FileMessageContent.java",
    "content": "/*\n * Copyright (c) 2020 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\n\n/**\n * 文件消息内容类\n * <p>\n * 表示文件类型的消息内容，继承自MediaMessageContent。\n * 包含文件名和文件大小信息。\n * </p>\n */\npublic class FileMessageContent extends MediaMessageContent {\n    private String name;\n    private int size;\n    private static final String FILE_NAME_PREFIX = \"[文件] \";\n\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.File;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setSearchableContent(name);\n        payload.setContent(size + \"\");\n\n        return payload;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public int getSize() {\n        return size;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public void setSize(int size) {\n        this.size = size;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n\n        if (payload.getSearchableContent().startsWith(FILE_NAME_PREFIX)) {\n            name = payload.getSearchableContent().substring(payload.getSearchableContent().indexOf(FILE_NAME_PREFIX) + FILE_NAME_PREFIX.length());\n        } else {\n            name = payload.getSearchableContent();\n        }\n        size = Integer.parseInt(payload.getContent());\n    }\n\n    @Override\n    protected int getMediaType() {\n        return ProtoConstants.MessageMediaType.FILE;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/ImageMessageContent.java",
    "content": "/*\n * Copyright (c) 2020 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\n\nimport java.util.Base64;\n\n/**\n * 图片消息内容类\n * <p>\n * 表示图片类型的消息内容，继承自MediaMessageContent。\n * 包含图片缩略图数据。\n * </p>\n */\npublic class ImageMessageContent extends MediaMessageContent {\n    private byte[] thumbnailBytes;\n\n\n    public void setThumbnailBytes(byte[] thumbnailBytes) {\n        this.thumbnailBytes = thumbnailBytes;\n    }\n\n    public byte[] getThumbnailBytes() {\n        return thumbnailBytes;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Image;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setSearchableContent(\"[图片]\");\n        if(thumbnailBytes != null) {\n            payload.setBase64edData(Base64.getEncoder().encodeToString(thumbnailBytes));\n        }\n\n        return payload;\n    }\n\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        if(payload.getBase64edData() != null) {\n            thumbnailBytes = Base64.getDecoder().decode(payload.getBase64edData());\n        }\n    }\n\n    @Override\n    protected int getMediaType() {\n        return ProtoConstants.MessageMediaType.IMAGE;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/LinkMessageContent.java",
    "content": "/*\n * Copyright (c) 2020 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport io.netty.util.internal.StringUtil;\nimport org.json.simple.JSONObject;\nimport org.json.simple.parser.JSONParser;\nimport org.json.simple.parser.ParseException;\n\nimport java.util.Base64;\n\n/**\n * 链接消息内容类\n * <p>\n * 表示链接分享类型的消息内容，包含标题、描述、URL和缩略图。\n * </p>\n */\npublic class LinkMessageContent extends MessageContent {\n    private String title;\n    private String contentDigest;\n    private String url;\n    private String thumbnailUrl;\n\n    public LinkMessageContent() {\n    }\n\n    public LinkMessageContent(String title, String url) {\n        this.title = title;\n        this.url = url;\n    }\n\n    public String getContentDigest() {\n        return contentDigest;\n    }\n\n    public void setContentDigest(String contentDigest) {\n        this.contentDigest = contentDigest;\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public String getThumbnailUrl() {\n        return thumbnailUrl;\n    }\n\n    public void setThumbnailUrl(String thumbnailUrl) {\n        this.thumbnailUrl = thumbnailUrl;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Link;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setSearchableContent(title);\n        JSONObject objWrite = new JSONObject();\n        objWrite.put(\"d\", contentDigest);\n        objWrite.put(\"u\", url);\n        objWrite.put(\"t\", thumbnailUrl);\n        payload.setBase64edData(Base64.getEncoder().encodeToString(objWrite.toString().getBytes()));\n\n        return payload;\n    }\n\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        title = payload.getSearchableContent();\n        try {\n            if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {\n                JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));\n                contentDigest = (String) jsonObject.get(\"d\");\n                url = (String) jsonObject.get(\"u\");\n                thumbnailUrl = (String) jsonObject.get(\"t\");\n            }\n        } catch (ParseException e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/LocationMessageContent.java",
    "content": "/*\n * Copyright (c) 2020 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport io.netty.util.internal.StringUtil;\nimport org.json.simple.JSONObject;\nimport org.json.simple.parser.JSONParser;\nimport org.json.simple.parser.ParseException;\n\nimport java.util.Base64;\n\n/**\n * 位置消息内容类\n * <p>\n * 表示位置类型的消息内容，包含标题、缩略图、经纬度信息。\n * </p>\n */\npublic class LocationMessageContent extends MessageContent {\n    private String title;\n    public byte[] thumbnailByte;\n    private double longitude;\n    private double latitude;\n\n    public LocationMessageContent() {\n    }\n\n    public String getTitle() {\n        return title;\n    }\n\n    public void setTitle(String title) {\n        this.title = title;\n    }\n\n    public byte[] getThumbnailByte() {\n        return thumbnailByte;\n    }\n\n    public void setThumbnailByte(byte[] thumbnailByte) {\n        this.thumbnailByte = thumbnailByte;\n    }\n\n    public double getLongitude() {\n        return longitude;\n    }\n\n    public void setLongitude(double longitude) {\n        this.longitude = longitude;\n    }\n\n    public double getLatitude() {\n        return latitude;\n    }\n\n    public void setLatitude(double latitude) {\n        this.latitude = latitude;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Location;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setSearchableContent(title);\n        payload.setBase64edData(Base64.getEncoder().encodeToString(this.thumbnailByte));\n\n        JSONObject objWrite = new JSONObject();\n        objWrite.put(\"lat\", latitude);\n        objWrite.put(\"long\", longitude);\n\n        payload.setContent(objWrite.toString());\n\n        return payload;\n    }\n\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        if (!StringUtil.isNullOrEmpty(payload.getBase64edData())) {\n            this.thumbnailByte = Base64.getDecoder().decode(payload.getBase64edData());\n        }\n        title = payload.getSearchableContent();\n        try {\n            if (payload.getContent() != null) {\n                JSONObject jsonObject = (JSONObject) new JSONParser().parse(payload.getContent());\n                latitude = (double) jsonObject.get(\"lat\");\n                longitude = (double) jsonObject.get(\"long\");\n            }\n        } catch (ParseException e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MediaMessageContent.java",
    "content": "package cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\n\n/**\n * 媒体消息内容基类\n * <p>\n * 所有媒体类型消息（图片、语音、视频、文件等）的抽象基类。\n * 包含媒体文件的远程URL信息。\n * </p>\n */\nabstract public class MediaMessageContent extends MessageContent {\n    private String remoteMediaUrl;\n\n    public String getRemoteMediaUrl() {\n        return remoteMediaUrl;\n    }\n\n    public void setRemoteMediaUrl(String remoteMediaUrl) {\n        this.remoteMediaUrl = remoteMediaUrl;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setRemoteMediaUrl(remoteMediaUrl);\n        payload.setMediaType(getMediaType());\n        return payload;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        remoteMediaUrl = payload.getRemoteMediaUrl();\n    }\n\n    protected abstract int getMediaType();\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MessageContent.java",
    "content": "package cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\n\nimport java.util.List;\n\n/**\n * 消息内容基类\n * <p>\n * 所有消息内容类型的抽象基类，定义了消息内容的通用属性和方法。\n * 子类需要实现具体的消息类型编码和解码逻辑。\n * </p>\n */\npublic abstract class MessageContent {\n    private int mentionedType;\n    private List<String> mentionedTargets;\n    private String extra;\n    public MessageContent mentionedType(int mentionedType) {\n        this.mentionedType = mentionedType;\n        return this;\n    }\n    public MessageContent mentionedTargets(List<String> mentionedTargets) {\n        this.mentionedTargets = mentionedTargets;\n        return this;\n    }\n\n    public MessageContent extra(String extra) {\n        this.extra = extra;\n        return this;\n    }\n\n    public MessagePayload encode() {\n        MessagePayload payload = new MessagePayload();\n        payload.setType(getContentType());\n        payload.setPersistFlag(getPersistFlag());\n        payload.setMentionedType(mentionedType);\n        payload.setMentionedTarget(mentionedTargets);\n        payload.setExtra(extra);\n        return payload;\n    }\n\n    protected void decode(MessagePayload payload) {\n        this.mentionedType = payload.getMentionedType();\n        this.mentionedTargets = payload.getMentionedTarget();\n        this.extra = payload.getExtra();\n    }\n    abstract public int getContentType();\n    abstract public int getPersistFlag();\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MessageContentFactory.java",
    "content": "package cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.Conversation;\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.WFCMessage;\nimport cn.wildfirechat.sdk.model.Message;\nimport cn.wildfirechat.sdk.utilities.ClassUtil;\n\nimport java.io.IOException;\nimport java.lang.reflect.Modifier;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * 消息内容工厂类\n * <p>\n * 负责消息内容的编码和解码，维护消息类型到消息内容类的映射关系。\n * 支持内置消息类型和自定义消息类型的注册。\n * </p>\n */\npublic class MessageContentFactory {\n    private static final Map<Integer, Class<? extends MessageContent>> contentClassMap = new ConcurrentHashMap<>();\n\n    private static List<Class> buildinMessageContents = Arrays.asList(\n        ArticlesMessageContent.class,\n        StreamTextGeneratedMessageContent.class,\n        CallStartMessageContent.class,\n        StreamTextGeneratingMessageContent.class,\n        CardMessageContent.class,\n        MultiCallOngoingMessageContent.class,\n        TextMessageContent.class,\n        DeleteMessageContent.class,\n        NotDeliveredMessageContent.class,\n        TipNotificationMessageContent.class,\n        FileMessageContent.class,\n        PTTSoundMessageContent.class,\n        TypingMessageContent.class,\n        ImageMessageContent.class,\n        RecallMessageContent.class,\n        UnknownMessageContent.class,\n        LinkMessageContent.class,\n        RichNotificationMessageContent.class,\n        VideoMessageContent.class,\n        LocationMessageContent.class,\n        SoundMessageContent.class,\n        StickerMessageContent.class\n    );\n\n    static  {\n        registerAllMessageContent();\n    }\n\n    public static Message decodeMessage(WFCMessage.Message protoMessage) {\n        Message message = new Message();\n        message.content = decodeMessageContent(protoMessage.getContent());\n        WFCMessage.Conversation protoConversation = protoMessage.getConversation();\n        message.conversation = new Conversation(protoConversation.getType(), protoConversation.getTarget(), protoConversation.getLine());\n        message.messageUid = protoMessage.getMessageId();\n        message.sender = protoMessage.getFromUser();\n        message.serverTime = protoMessage.getServerTimestamp();\n        message.toUsers = protoMessage.getToList();\n        return message;\n    }\n\n    public static MessageContent decodeMessageContent(WFCMessage.MessageContent protoMessageContent) {\n        MessagePayload payload = MessagePayload.fromProtoMessageContent(protoMessageContent);\n        return decodeMessageContent(payload);\n    }\n\n    public static MessageContent decodeMessageContent(MessagePayload messagePayload) {\n        Class<? extends MessageContent> cls = contentClassMap.get(messagePayload.getType());\n        MessageContent messageContent;\n        if(cls != null) {\n            try {\n                messageContent = cls.newInstance();\n            } catch (InstantiationException e) {\n                throw new RuntimeException(e);\n            } catch (IllegalAccessException e) {\n                throw new RuntimeException(e);\n            }\n        } else {\n            messageContent = new UnknownMessageContent();\n        }\n        messageContent.decode(messagePayload);\n        return messageContent;\n    }\n\n    public static void registerCustomMessageContent(Class<? extends MessageContent> cls) throws Exception {\n        MessageContent content = cls.newInstance();\n        contentClassMap.put(content.getContentType(), cls);\n    }\n\n    private static void registerAllMessageContent() {\n        try {\n            for (Class buildinMessageContent : buildinMessageContents) {\n                MessageContent content = (MessageContent)buildinMessageContent.newInstance();\n                contentClassMap.put(content.getContentType(), buildinMessageContent);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        try {\n            for (Class cls : ClassUtil.getAllAssignedClass(MessageContent.class)) {\n                if(!Modifier.isAbstract(cls.getModifiers())) {\n                    try {\n                        MessageContent content = (MessageContent)cls.newInstance();\n                        contentClassMap.put(content.getContentType(), cls);\n                    } catch (InstantiationException e) {\n                        e.printStackTrace();\n                    } catch (IllegalAccessException e) {\n                        e.printStackTrace();\n                    }\n                }\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        } catch (ClassNotFoundException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/MultiCallOngoingMessageContent.java",
    "content": "/*\n * Copyright (c) 2022 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\nimport org.json.simple.parser.JSONParser;\nimport org.json.simple.parser.ParseException;\n\nimport java.util.ArrayList;\nimport java.util.Base64;\nimport java.util.List;\n\n/**\n * 多人通话进行中消息内容类\n * <p>\n * 表示多人音视频通话进行中的状态消息。\n * 包含通话ID、发起者、是否仅语音、参与者列表等信息。\n * </p>\n */\npublic class MultiCallOngoingMessageContent extends MessageContent {\n    private String callId;\n    private String initiator;\n    private boolean audioOnly;\n    private List<String> targets;\n\n    public MultiCallOngoingMessageContent() {\n    }\n\n    public MultiCallOngoingMessageContent(String callId, String initiator, boolean audioOnly, List<String> targets) {\n        this.callId = callId;\n        this.initiator = initiator;\n        this.audioOnly = audioOnly;\n        this.targets = targets;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Call_Multi_Call_Ongoing;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Transparent;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setContent(callId);\n        JSONObject object = new JSONObject();\n        object.put(\"initiator\", this.initiator);\n        JSONArray arr = new JSONArray();\n        for (int i = 0; i < targets.size(); i++) {\n            arr.add(i, targets.get(i));\n        }\n        object.put(\"targets\", arr);\n        object.put(\"audioOnly\", this.audioOnly ? 1 : 0);\n        payload.setBase64edData(Base64.getEncoder().encodeToString(object.toString().getBytes()));\n\n        return payload;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        this.callId = payload.getContent();\n        try {\n            JSONObject object = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));\n            this.initiator = (String) object.get(\"initiator\");\n            this.targets = new ArrayList<>();\n            JSONArray array = (JSONArray) object.get(\"targets\");\n            if (array != null) {\n                for (int i = 0; i < array.size(); i++) {\n                    targets.add((String) array.get(i));\n                }\n            }\n            this.audioOnly = (int)object.get(\"audioOnly\") == 1;\n        } catch (ParseException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public String getCallId() {\n        return callId;\n    }\n\n    public void setCallId(String callId) {\n        this.callId = callId;\n    }\n\n    public String getInitiator() {\n        return initiator;\n    }\n\n    public void setInitiator(String initiator) {\n        this.initiator = initiator;\n    }\n\n    public boolean isAudioOnly() {\n        return audioOnly;\n    }\n\n    public void setAudioOnly(boolean audioOnly) {\n        this.audioOnly = audioOnly;\n    }\n\n    public List<String> getTargets() {\n        return targets;\n    }\n\n    public void setTargets(List<String> targets) {\n        this.targets = targets;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/NotDeliveredMessageContent.java",
    "content": "/*\n * Copyright (c) 2024 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\nimport org.json.simple.parser.JSONParser;\nimport org.json.simple.parser.ParseException;\n\nimport java.util.ArrayList;\nimport java.util.Base64;\nimport java.util.List;\n\n/**\n * 消息未送达通知类\n * <p>\n * 表示消息未能成功送达的通知，包含失败原因和失败用户列表。\n * 用于跨域消息投递失败的场景。\n * </p>\n */\npublic class NotDeliveredMessageContent extends MessageContent {\n    // 请求的类型，1 发送消息，2 撤回消息，3 删除消息\n    private int type;\n\n    // 发送的消息 uid\n    private long messageUid;\n\n    // 是全部失败，还是部分失败\n    private boolean allFailure;\n\n    // 部分失败时，失败的用户 id 列表\n    private List<String> userIds;\n\n    // 归属IM服务请求桥接服务出现的错误，有可能是桥接服务没有配置，或者不可用。\n    private int localImErrorCode;\n\n    // 归属桥接服务出现的错误\n    private int localBridgeErrorCode;\n\n    // 远端桥接服务出现的错误\n    private int remoteBridgeErrorCode;\n\n    // 远端IM服务出现的错误\n    private int remoteServerErrorCode;\n\n    // 错误提示信息\n    private String errorMessage;\n\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Not_Delivered;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        JSONObject obj = new JSONObject();\n        obj.put(\"mid\", this.messageUid);\n        obj.put(\"all\", this.allFailure);\n        obj.put(\"us\", this.userIds);\n        obj.put(\"lme\", this.localImErrorCode);\n        obj.put(\"lbe\", this.localBridgeErrorCode);\n        obj.put(\"rbe\", this.remoteBridgeErrorCode);\n        obj.put(\"rme\", this.remoteServerErrorCode);\n        obj.put(\"em\", this.errorMessage);\n        payload.setBase64edData(Base64.getEncoder().encodeToString(obj.toString().getBytes()));\n        return payload;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        try {\n                super.decode(payload);\n                JSONObject obj = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));\n                this.messageUid = (long) obj.get(\"mid\");\n                this.allFailure = (boolean) obj.get(\"all\");\n                this.userIds = new ArrayList<>();\n                JSONArray arr = (JSONArray) obj.get(\"us\");\n                if (arr != null) {\n                    for (int i = 0; i < arr.size(); i++) {\n                        this.userIds.add((String) arr.get(i));\n                    }\n                }\n                this.localImErrorCode = (int) obj.get(\"lme\");\n                this.localBridgeErrorCode = (int) obj.get(\"lbe\");\n                this.remoteBridgeErrorCode = (int) obj.get(\"rbe\");\n                this.remoteServerErrorCode = (int) obj.get(\"rme\");\n                this.errorMessage = (String) obj.get(\"em\");\n        } catch (ParseException e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/PTTSoundMessageContent.java",
    "content": "/*\n * Copyright (c) 2021 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport org.json.simple.JSONObject;\n\n/**\n * 对讲语音消息内容类\n * <p>\n * 表示对讲语音类型的消息内容，继承自SoundMessageContent。\n * 用于实时对讲场景。\n * </p>\n */\npublic class PTTSoundMessageContent extends SoundMessageContent {\n\n    public PTTSoundMessageContent() {\n        super();\n    }\n\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setSearchableContent(\"[对讲语音]\");\n\n        return payload;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Ptt_Voice;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/RecallMessageContent.java",
    "content": "package cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport org.apache.http.util.TextUtils;\nimport org.json.simple.JSONObject;\nimport org.json.simple.parser.JSONParser;\nimport org.json.simple.parser.ParseException;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\n\n/**\n * 撤回消息内容类\n * <p>\n * 表示消息撤回通知，包含被撤回消息的原始信息。\n * </p>\n */\npublic class RecallMessageContent extends MessageContent {\n    private long messageId;\n    private String operatorId;\n\n\n    private String originalSender;\n\n    private int originalContentType;\n    private String originalSearchableContent;\n    private String originalContent;\n    private String originalExtra;\n    private byte[] originalBinaryContent;\n    private int originalMediaType;\n    private String originalMediaUrl;\n    private long originalMessageTimestamp;\n\n    //必须有个空的构造函数\n    public RecallMessageContent() {\n    }\n\n    public long getMessageId() {\n        return messageId;\n    }\n\n    public String getOperatorId() {\n        return operatorId;\n    }\n\n    public String getOriginalSender() {\n        return originalSender;\n    }\n\n    public int getOriginalContentType() {\n        return originalContentType;\n    }\n\n    public String getOriginalSearchableContent() {\n        return originalSearchableContent;\n    }\n\n    public String getOriginalContent() {\n        return originalContent;\n    }\n\n    public String getOriginalExtra() {\n        return originalExtra;\n    }\n\n    public long getOriginalMessageTimestamp() {\n        return originalMessageTimestamp;\n    }\n\n    public byte[] getOriginalBinaryContent() {\n        return originalBinaryContent;\n    }\n\n    public int getOriginalMediaType() {\n        return originalMediaType;\n    }\n\n    public String getOriginalMediaUrl() {\n        return originalMediaUrl;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Recall;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        throw new RuntimeException(\"Recall message cannot encode\");\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        operatorId = payload.getContent();\n        messageId = Long.parseLong(new String(Base64.getDecoder().decode(payload.getBase64edData()), StandardCharsets.UTF_8));\n        if(!TextUtils.isEmpty(payload.getExtra())) {\n            try {\n                JSONObject dictionary = (JSONObject) new JSONParser().parse(payload.getExtra());\n                originalSender = (String) dictionary.get(\"s\");\n                if (dictionary.containsKey(\"t\")) {\n                    originalContentType = ((Number) dictionary.get(\"t\")).intValue();\n                }\n                originalSearchableContent = (String) dictionary.get(\"sc\");\n                originalContent = (String) dictionary.get(\"c\");\n                originalExtra = (String) dictionary.get(\"e\");\n                if (dictionary.containsKey(\"ts\")) {\n                    originalMessageTimestamp = ((Number) dictionary.get(\"ts\")).longValue();\n                }\n                if (dictionary.containsKey(\"mt\")) {\n                    originalMediaType = ((Number) dictionary.get(\"mt\")).intValue();\n                }\n                originalMediaUrl = (String) dictionary.get(\"mu\");\n                if (dictionary.containsKey(\"mb\")) {\n                    originalBinaryContent = Base64.getDecoder().decode((String) dictionary.get(\"mb\"));\n                }\n            } catch (ParseException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/RichNotificationMessageContent.java",
    "content": "package cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport io.netty.util.internal.StringUtil;\nimport org.json.simple.JSONArray;\nimport org.json.simple.JSONObject;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\n\n/**\n * 富媒体通知消息内容类\n * <p>\n * 表示富媒体类型的消息内容，包含标题、描述、扩展信息等。\n * 支持自定义数据和扩展字段。\n * </p>\n */\npublic class RichNotificationMessageContent extends MessageContent {\n    private String title;\n    private String desc;\n    private String remark;\n    private JSONArray datas;\n    private String exName;\n    private String exPortrait;\n    private String exUrl;\n    private String appId;\n\n    //必须有个空的构造函数\n    public RichNotificationMessageContent() {\n    }\n\n    public RichNotificationMessageContent(String title, String desc, String exUrl) {\n        this.title = title;\n        this.desc = desc;\n        this.exUrl = exUrl;\n    }\n\n    public RichNotificationMessageContent title(String title) {\n        this.title = title;\n        return this;\n    }\n\n    public RichNotificationMessageContent desc(String desc) {\n        this.desc = desc;\n        return this;\n    }\n\n    public RichNotificationMessageContent exUrl(String exUrl) {\n        this.exUrl = exUrl;\n        return this;\n    }\n\n    public RichNotificationMessageContent remark(String remark) {\n        this.remark = remark;\n        return this;\n    }\n    public RichNotificationMessageContent exName(String exName) {\n        this.exName = exName;\n        return this;\n    }\n    public RichNotificationMessageContent exPortrait(String exPortrait) {\n        this.exPortrait = exPortrait;\n        return this;\n    }\n    public RichNotificationMessageContent appId(String appId) {\n        this.appId = appId;\n        return this;\n    }\n    public RichNotificationMessageContent addItem(String key, String value) {\n        return addItem(key, value, null);\n    }\n    public RichNotificationMessageContent addItem(String key, String value, String color) {\n        if(this.datas == null) {\n            this.datas = new JSONArray();\n        }\n        JSONObject item = new JSONObject();\n        item.put(\"key\", key);\n        item.put(\"value\", value == null ? \"\" : value);\n        if(!StringUtil.isNullOrEmpty(color)) {\n            item.put(\"color\", color);\n        }\n        this.datas.add(item);\n        return this;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Rich_Notification;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setPushContent(title);\n        payload.setContent(desc);\n        JSONObject jsonObject = new JSONObject();\n        if(!StringUtil.isNullOrEmpty(remark))\n            jsonObject.put(\"remark\", remark);\n        if(!StringUtil.isNullOrEmpty(exName))\n            jsonObject.put(\"exName\", exName);\n        if(!StringUtil.isNullOrEmpty(exPortrait))\n            jsonObject.put(\"exPortrait\", exPortrait);\n        if(!StringUtil.isNullOrEmpty(exUrl))\n            jsonObject.put(\"exUrl\", exUrl);\n        if(!StringUtil.isNullOrEmpty(appId))\n            jsonObject.put(\"appId\", appId);\n        if(datas != null && !datas.isEmpty())\n            jsonObject.put(\"datas\", datas);\n\n        payload.setBase64edData(Base64.getEncoder().encodeToString(jsonObject.toJSONString().getBytes(StandardCharsets.UTF_8)));\n\n        return payload;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/SoundMessageContent.java",
    "content": "package cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport org.json.simple.JSONObject;\n\n/**\n * 语音消息内容类\n * <p>\n * 表示语音类型的消息内容，继承自MediaMessageContent。\n * 包含语音时长信息。\n * </p>\n */\npublic class SoundMessageContent extends MediaMessageContent {\n    private int duration;\n\n    //必须有个空的构造函数\n    public SoundMessageContent() {\n    }\n\n    public SoundMessageContent(int duration) {\n        this.duration = duration;\n    }\n\n    public int getDuration() {\n        return duration;\n    }\n\n    public void setDuration(int duration) {\n        this.duration = duration;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Voice;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"duration\", duration);\n        payload.setContent(jsonObject.toJSONString());\n        return payload;\n    }\n\n    @Override\n    protected int getMediaType() {\n        return ProtoConstants.MessageMediaType.VOICE;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StickerMessageContent.java",
    "content": "/*\n * Copyright (c) 2020 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport org.json.simple.JSONObject;\nimport org.json.simple.parser.JSONParser;\nimport org.json.simple.parser.ParseException;\n\nimport java.util.Base64;\n\n/**\n * 动态表情消息内容类\n * <p>\n * 表示动态表情（贴纸）类型的消息内容，继承自MediaMessageContent。\n * 包含表情图片的宽高信息。\n * </p>\n */\npublic class StickerMessageContent extends MediaMessageContent {\n    public int width;\n    public int height;\n\n    public int getWidth() {\n        return width;\n    }\n\n    public void setWidth(int width) {\n        this.width = width;\n    }\n\n    public int getHeight() {\n        return height;\n    }\n\n    public void setHeight(int height) {\n        this.height = height;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setSearchableContent(\"[动态表情]\");\n        JSONObject objWrite = new JSONObject();\n        objWrite.put(\"x\", width);\n        objWrite.put(\"y\", height);\n        payload.setBase64edData(Base64.getEncoder().encodeToString(objWrite.toString().getBytes()));\n\n        return payload;\n    }\n\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        try {\n            JSONObject jsonObject = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(payload.getBase64edData())));\n            width = (int) jsonObject.get(\"x\");\n            height = (int) jsonObject.get(\"y\");\n        } catch (ParseException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    protected int getMediaType() {\n        return ProtoConstants.MessageMediaType.STICKER;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Sticker;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StreamTextGeneratedMessageContent.java",
    "content": "package cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\n\n/**\n * 流式文本已生成消息内容类\n * <p>\n * 表示AI流式文本生成的结果消息。\n * 包含生成的完整文本内容和流ID。\n * </p>\n */\npublic class StreamTextGeneratedMessageContent extends MessageContent {\n    private String text;\n    private String streamId;\n\n    //必须有个空的构造函数\n    public StreamTextGeneratedMessageContent() {\n    }\n\n    public StreamTextGeneratedMessageContent(String text, String streamId) {\n        this.text = text;\n        this.streamId = streamId;\n    }\n\n    public StreamTextGeneratedMessageContent text(String text) {\n        this.text = text;\n        return this;\n    }\n\n    public StreamTextGeneratedMessageContent streamId(String streamId) {\n        this.streamId = streamId;\n        return this;\n    }\n\n    @Override\n    public int getContentType() {\n            return ProtoConstants.ContentType.StreamingText_Generated;\n    }\n\n    @Override\n    public int getPersistFlag() {\n            return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        this.streamId = payload.getContent();\n        this.text = payload.getSearchableContent();\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setSearchableContent(text);\n        payload.setContent(streamId);\n        return payload;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/StreamTextGeneratingMessageContent.java",
    "content": "package cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\n\n/**\n * 流式文本生成中消息内容类\n * <p>\n * 表示AI流式文本正在生成的状态消息。\n * 包含生成的文本内容和流ID。\n * </p>\n */\npublic class StreamTextGeneratingMessageContent extends MessageContent {\n    private String text;\n    private String streamId;\n\n    //必须有个空的构造函数\n    public StreamTextGeneratingMessageContent() {\n    }\n\n    public StreamTextGeneratingMessageContent(String text, String streamId) {\n        this.text = text;\n        this.streamId = streamId;\n    }\n\n    public StreamTextGeneratingMessageContent text(String text) {\n        this.text = text;\n        return this;\n    }\n\n    public StreamTextGeneratingMessageContent streamId(String streamId) {\n        this.streamId = streamId;\n        return this;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.StreamingText_Generationg;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Transparent;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        streamId = payload.getContent();\n        text = payload.getSearchableContent();\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setSearchableContent(text);\n        payload.setContent(streamId);\n        return payload;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TextMessageContent.java",
    "content": "package cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport cn.wildfirechat.sdk.model.QuoteInfo;\nimport org.apache.http.util.TextUtils;\nimport org.json.simple.JSONObject;\nimport org.json.simple.parser.JSONParser;\nimport org.json.simple.parser.ParseException;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Base64;\n\n/**\n * 文本消息内容类\n * <p>\n * 表示文本类型的消息内容，支持纯文本和引用回复功能。\n * </p>\n */\npublic class TextMessageContent extends MessageContent {\n    private String text;\n    private QuoteInfo quoteInfo;\n\n    //必须有个空的构造函数\n    public TextMessageContent() {\n    }\n\n    public TextMessageContent(String text) {\n        this.text = text;\n    }\n\n    public TextMessageContent text(String text) {\n        this.text = text;\n        return this;\n    }\n\n    public String getText() {\n        return text;\n    }\n\n    public void setText(String text) {\n        this.text = text;\n    }\n\n    public QuoteInfo getQuoteInfo() {\n        return quoteInfo;\n    }\n\n    public void setQuoteInfo(QuoteInfo quoteInfo) {\n        this.quoteInfo = quoteInfo;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Text;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setSearchableContent(text);\n        if(quoteInfo != null) {\n            payload.setBase64edData(Base64.getEncoder().encodeToString(quoteInfo.encode().toJSONString().getBytes(StandardCharsets.UTF_8)));\n        }\n        return payload;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        text = payload.getSearchableContent();\n        if(!TextUtils.isEmpty(payload.getBase64edData())) {\n            String jsonStr = new String(Base64.getDecoder().decode(payload.getBase64edData()), StandardCharsets.UTF_8);\n            try {\n                JSONObject jsonObject = (JSONObject) new JSONParser().parse(jsonStr);\n                quoteInfo = new QuoteInfo();\n                quoteInfo.decode(jsonObject);\n            } catch (ParseException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TipNotificationMessageContent.java",
    "content": "/*\n * Copyright (c) 2020 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\n\n/**\n * 提示通知消息内容类\n * <p>\n * 表示提示类型的消息内容，用于显示各种提示信息（如\"对方正在输入\"等）。\n * </p>\n */\npublic class TipNotificationMessageContent extends MessageContent {\n    public String tip;\n\n    public TipNotificationMessageContent() {\n    }\n\n    public String getTip() {\n        return tip;\n    }\n\n    public void setTip(String tip) {\n        this.tip = tip;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setContent(tip);\n\n        return payload;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        tip = payload.getContent();\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Tip;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/TypingMessageContent.java",
    "content": "/*\n * Copyright (c) 2020 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\n\n/**\n * 正在输入消息内容类\n * <p>\n * 表示正在输入的状态消息，用于显示对方正在输入的提示。\n * 支持多种输入类型：文本、语音、视频、位置、文件等。\n * </p>\n */\npublic class TypingMessageContent extends MessageContent {\n    public static final int TYPING_TEXT = 0;\n    public static final int TYPING_VOICE = 1;\n    public static final int TYPING_CAMERA = 2;\n    public static final int TYPING_LOCATION = 3;\n    public static final int TYPING_FILE = 4;\n\n    private int typingType;\n\n    public TypingMessageContent() {\n    }\n\n    public TypingMessageContent(int typingType) {\n        this.typingType = typingType;\n    }\n\n    public int getTypingType() {\n        return typingType;\n    }\n\n    public void setTypingType(int typingType) {\n        this.typingType = typingType;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Typing;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Transparent;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setContent(typingType + \"\");\n        return payload;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        typingType = Integer.parseInt(payload.getContent());\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/UnknownMessageContent.java",
    "content": "package cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\n\n/**\n * 未知消息内容类\n * <p>\n * 表示未知类型的消息内容，用于处理无法识别的消息类型。\n * 保存原始的消息负载以便后续处理。\n * </p>\n */\npublic class UnknownMessageContent extends MessageContent {\n    private MessagePayload orignalPayload;\n\n    //必须有个空的构造函数\n    public UnknownMessageContent() {\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Unknown;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        return orignalPayload;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        this.orignalPayload = payload;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/messagecontent/VideoMessageContent.java",
    "content": "/*\n * Copyright (c) 2020 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.messagecontent;\n\nimport cn.wildfirechat.pojos.MessagePayload;\nimport cn.wildfirechat.proto.ProtoConstants;\nimport org.json.simple.JSONObject;\nimport org.json.simple.parser.JSONParser;\nimport org.json.simple.parser.ParseException;\n\nimport java.util.Base64;\n\n\n/**\n * 创建者 heavyrain lee\n *\n * @refactor dhl\n * 添加小视频的宽高，时长\n */\n\n/**\n * 视频消息内容类\n * <p>\n * 表示视频类型的消息内容，继承自MediaMessageContent。\n * 包含视频缩略图和时长信息。\n * </p>\n */\npublic class VideoMessageContent extends MediaMessageContent {\n    private byte[] thumbnailBytes;\n    private long duration ;\n\n    //必须有个空的构造函数\n    public VideoMessageContent() {\n    }\n\n    public VideoMessageContent setThumbnailBytes(byte[] thumbnailBytes) {\n        this.thumbnailBytes = thumbnailBytes;\n        return this;\n    }\n\n    public byte[] getThumbnailBytes() {\n        return thumbnailBytes;\n    }\n\n    public void setDuration(long duration) {\n        this.duration = duration;\n    }\n\n    public long getDuration() {\n        return duration;\n    }\n\n    @Override\n    public int getContentType() {\n        return ProtoConstants.ContentType.Video;\n    }\n\n    @Override\n    public int getPersistFlag() {\n        return ProtoConstants.PersistFlag.Persist_And_Count;\n    }\n\n    @Override\n    public MessagePayload encode() {\n        MessagePayload payload = super.encode();\n        payload.setSearchableContent(\"[视频]\");\n\n        payload.setBase64edData(Base64.getEncoder().encodeToString(thumbnailBytes));\n\n        JSONObject objWrite = new JSONObject();\n        objWrite.put(\"d\", duration);\n        objWrite.put(\"duration\", duration);\n        payload.setContent(objWrite.toJSONString());\n\n        return payload;\n    }\n\n    @Override\n    public void decode(MessagePayload payload) {\n        super.decode(payload);\n        thumbnailBytes = Base64.getDecoder().decode(payload.getBase64edData());\n        try {\n            JSONObject jsonObject = (JSONObject) new JSONParser().parse(payload.getContent());\n            if(jsonObject.containsKey(\"d\")) {\n                duration = (long) jsonObject.get(\"d\");\n            } else {\n                duration = (long) jsonObject.get(\"duration\");\n            }\n        } catch (ParseException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    protected int getMediaType() {\n        return ProtoConstants.MessageMediaType.VIDEO;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/model/IMResult.java",
    "content": "package cn.wildfirechat.sdk.model;\n\nimport cn.wildfirechat.common.ErrorCode;\n\n/**\n * IM结果类\n * <p>\n * 泛型类，用于封装所有API调用的返回结果。\n * 包含错误码、错误消息和返回数据。\n * </p>\n * @param <T> 返回数据的类型\n */\npublic class IMResult<T> {\n\n    public int code;\n    public String msg;\n    public T result;\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public ErrorCode getErrorCode() {\n        return ErrorCode.fromCode(code);\n    }\n\n    public String getMsg() {\n        return msg;\n    }\n\n    public void setMsg(String msg) {\n        this.msg = msg;\n    }\n\n    public T getResult() {\n        return result;\n    }\n\n    public void setResult(T result) {\n        this.result = result;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/model/Message.java",
    "content": "package cn.wildfirechat.sdk.model;\n\nimport cn.wildfirechat.pojos.Conversation;\nimport cn.wildfirechat.sdk.messagecontent.MessageContent;\n\nimport java.util.List;\n\n/**\n * 消息类\n * <p>\n * 表示一条完整的消息，包含会话信息、消息内容、发送者、时间等。\n * </p>\n */\npublic class Message {\n    public Conversation conversation;\n    public MessageContent content;\n    public long messageUid;\n    public String sender;\n    public long serverTime;\n    public List<String> toUsers;\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/model/QuoteInfo.java",
    "content": "/*\n * Copyright (c) 2020 WildFireChat. All rights reserved.\n */\n\npackage cn.wildfirechat.sdk.model;\n\nimport org.json.simple.JSONObject;\n\n/**\n * 引用消息信息类\n * <p>\n * 封装被引用消息的信息，包括消息UID、发送者信息、消息摘要等。\n * 用于回复消息时引用原消息内容。\n * </p>\n */\npublic class QuoteInfo {\n    private long messageUid;\n    private String userId;\n    private String userDisplayName;\n    private String messageDigest;\n\n    public long getMessageUid() {\n        return messageUid;\n    }\n\n    public void setMessageUid(long messageUid) {\n        this.messageUid = messageUid;\n    }\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getUserDisplayName() {\n        return userDisplayName;\n    }\n\n    public void setUserDisplayName(String userDisplayName) {\n        this.userDisplayName = userDisplayName;\n    }\n\n    public String getMessageDigest() {\n        return messageDigest;\n    }\n\n    public void setMessageDigest(String messageDigest) {\n        this.messageDigest = messageDigest;\n    }\n\n    public JSONObject encode() {\n        JSONObject object = new JSONObject();\n        object.put(\"u\", messageUid);\n        object.put(\"i\", userId);\n        object.put(\"n\", userDisplayName);\n        object.put(\"d\", messageDigest);\n        JSONObject quote = new JSONObject();\n        quote.put(\"quote\", object);\n        return quote;\n    }\n\n    public void decode(JSONObject object) {\n        JSONObject quote = (JSONObject)object.get(\"quote\");\n        if(quote != null) {\n            messageUid = (long) quote.get(\"u\");\n            userId = (String) quote.get(\"i\");\n            userDisplayName = (String) quote.get(\"n\");\n            messageDigest = (String) quote.get(\"d\");\n        }\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/utilities/AdminHttpUtils.java",
    "content": "package cn.wildfirechat.sdk.utilities;\n\nimport cn.wildfirechat.sdk.model.IMResult;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.DefaultHttpRequestRetryHandler;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.impl.conn.PoolingHttpClientConnectionManager;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.security.SecureRandom;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * 管理员HTTP工具类\n * <p>\n * 提供管理员API调用的HTTP工具方法，包括初始化、请求签名、HTTP请求等。\n * 继承自HttpUtils，专门用于管理员接口的调用。\n * </p>\n */\npublic class AdminHttpUtils extends HttpUtils {\n    // ======================== 常量定义（消除硬编码）========================\n    private static final Logger LOG = LoggerFactory.getLogger(AdminHttpUtils.class);\n\n    // 连接池配置常量\n    private static final int DEFAULT_CONNECT_TIMEOUT = 15000;\n    private static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT = 3000;\n    private static final int DEFAULT_SOCKET_TIMEOUT = 15000;\n    private static final int MAX_CONN_TOTAL = 100;\n    private static final int MAX_CONN_PER_ROUTE = 50;\n    private static final long IDLE_CONNECTION_EVICT_TIME = 60L;\n    private static final int VALIDATE_AFTER_INACTIVITY = 1000;\n    private static final SecureRandom SECURE_RANDOM = new SecureRandom();\n    private static final int NONCE_MAX_RANGE = 1000000;\n\n    // ======================== 线程安全的全局变量 ========================\n    private static volatile String adminUrl;\n    private static volatile String adminSecret;\n\n    public static CloseableHttpClient getHttpClient() {\n        return httpClient;\n    }\n\n    private static volatile CloseableHttpClient httpClient;\n\n\n    // ======================== 初始化方法 ========================\n    public static void init(String url, String secret) {\n        init(url, secret, DEFAULT_SOCKET_TIMEOUT);\n    }\n\n    /**\n     * 初始化HTTP客户端和配置\n     * @param url IM服务管理地址\n     * @param secret 管理密钥\n     * @param timeout 套接字超时时间（毫秒）\n     */\n    public static synchronized void init(String url, String secret, int timeout) {\n        // 参数校验\n        if (isNullOrEmpty(url) || isNullOrEmpty(secret)) {\n            throw new IllegalArgumentException(\"IM服务地址或密钥不能为空\");\n        }\n        adminUrl = url.trim();\n        adminSecret = secret.trim();\n\n        // 若已存在HttpClient，先关闭再重新初始化（支持配置更新）\n        if (httpClient != null) {\n            try {\n                httpClient.close();\n            } catch (IOException e) {\n                LOG.error(\"关闭旧HttpClient连接池失败\", e);\n            }\n        }\n\n        // 初始化连接池\n        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();\n        cm.setValidateAfterInactivity(VALIDATE_AFTER_INACTIVITY);\n\n        // 构建请求配置\n        RequestConfig requestConfig = RequestConfig.custom()\n            .setConnectTimeout(DEFAULT_CONNECT_TIMEOUT)\n            .setSocketTimeout(timeout)\n            .setConnectionRequestTimeout(DEFAULT_CONNECTION_REQUEST_TIMEOUT)\n            .build();\n\n        // 构建HttpClient\n        httpClient = HttpClients.custom()\n            .setDefaultRequestConfig(requestConfig)\n            .setConnectionManager(cm)\n            .evictExpiredConnections()\n            .evictIdleConnections(IDLE_CONNECTION_EVICT_TIME, TimeUnit.SECONDS)\n            .setRetryHandler(new DefaultHttpRequestRetryHandler(3, false)) // 重试3次，不重试IO异常\n            .setMaxConnTotal(MAX_CONN_TOTAL)\n            .setMaxConnPerRoute(MAX_CONN_PER_ROUTE)\n            .build();\n\n        LOG.info(\"AdminHttpUtils初始化完成，IM服务地址：{}\", adminUrl);\n    }\n\n    // ======================== HTTP GET请求 ========================\n    public static <T> IMResult<T> httpGet(String path, Class<T> clazz) throws Exception {\n        // 前置校验\n        validateInitStatus(adminUrl, adminSecret, httpClient);\n        if (isNullOrEmpty(path)) {\n            throw new IllegalArgumentException(\"请求路径不能为空\");\n        }\n\n        HttpGet httpGet = new HttpGet(adminUrl + path);\n        try {\n            HttpResponse response = httpClient.execute(httpGet);\n            return handleResponse(response, clazz, adminUrl, adminSecret);\n        } catch (Exception e) {\n            LOG.error(\"HTTP GET请求失败，路径：{}\", path, e);\n            throw new Exception(\"HTTP GET请求异常：\" + e.getMessage(), e);\n        } finally {\n            httpGet.releaseConnection();\n        }\n    }\n\n    // ======================== HTTP JSON POST请求 ========================\n    public static <T> IMResult<T> httpJsonPost(String path, Object object, Class<T> clazz) throws Exception {\n        return httpJsonPost(adminUrl, adminSecret, httpClient, path, object, clazz, httpPost -> {\n            // 构建签名头\n            int nonce = SECURE_RANDOM.nextInt(NONCE_MAX_RANGE) + 1; // 安全随机数\n            long timestamp = System.currentTimeMillis();\n            String signStr = nonce + \"|\" + adminSecret + \"|\" + timestamp;\n            String sign = DigestUtils.sha1Hex(signStr);\n\n            // 设置请求头\n            httpPost.setHeader(\"Content-type\", \"application/json; charset=utf-8\");\n            httpPost.setHeader(\"Connection\", \"Keep-Alive\");\n            httpPost.setHeader(\"nonce\", String.valueOf(nonce));\n            httpPost.setHeader(\"timestamp\", String.valueOf(timestamp));\n            httpPost.setHeader(\"sign\", sign);\n        });\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/utilities/ChannelHttpUtils.java",
    "content": "package cn.wildfirechat.sdk.utilities;\n\nimport cn.wildfirechat.sdk.model.IMResult;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport ikidou.reflect.TypeBuilder;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.HttpStatus;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.DefaultHttpRequestRetryHandler;\nimport org.apache.http.impl.client.HttpClientBuilder;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.impl.conn.PoolingHttpClientConnectionManager;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.BufferedReader;\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.lang.reflect.Type;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.nio.charset.Charset;\nimport java.util.concurrent.TimeUnit;\n\n\n/**\n * 频道HTTP工具类\n * <p>\n * 提供频道API调用的HTTP工具方法，包括初始化、请求签名、HTTP请求等。\n * 继承自HttpUtils并实现Closeable接口，专门用于频道接口的调用。\n * </p>\n */\npublic class ChannelHttpUtils extends HttpUtils implements Closeable {\n    private static final Logger LOG = LoggerFactory.getLogger(ChannelHttpUtils.class);\n\n    private String imurl;\n    private String channelId;\n    private String channelSecret;\n    private final CloseableHttpClient httpClient;\n\n    private final int port;\n\n    private void checkPort() {\n        if (port != 80 && port != 443 && port != -1) {\n            if (port == 18080) {\n                LOG.warn(\"您传入的频道API地址中的端口是18080，18080端口默认为管理API端口，频道API端口应该为IM服务的HTTP端口，默认为80，请确认是否使用错误！\");\n            } else {\n                LOG.warn(\"您传入的频道API地址中的端口不是80/443，频道API的端口和客户端使用端口一样，都应该为IM服务的HTTP端口，默认为80，请确实是否正确？如果您定制化了IM服务端口或者使用其他端口反向代理IM服务的HTTP端口请忽略此提示。\");\n            }\n        }\n    }\n\n    public ChannelHttpUtils(String imurl, String channelId, String secret) {\n        this.imurl = imurl.trim();\n        this.channelId = channelId.trim();\n        this.channelSecret = secret.trim();\n        try {\n            URL u = new URL(this.imurl);\n            int port = u.getPort();\n            if(port == -1) {\n                port = u.getDefaultPort();\n            }\n            this.port = port;\n        } catch (MalformedURLException e) {\n            throw new RuntimeException(e);\n        }\n        checkPort();\n        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();\n        cm.setValidateAfterInactivity(1000);\n        int connectTimeout = 5000; // 连接超时时间\n        int socketTimeout = 15000; // 请求超时时间\n        int connectionRequestTimeout = 3000; // 从连接池获取连接的超时时间\n        RequestConfig requestConfig = RequestConfig.custom()\n            .setConnectTimeout(connectTimeout)\n            .setSocketTimeout(socketTimeout)\n            .setConnectionRequestTimeout(connectionRequestTimeout)\n            .build();\n        httpClient = HttpClients.custom()\n            .setDefaultRequestConfig(requestConfig)\n            .setConnectionManager(cm)\n            .evictExpiredConnections()\n            .evictIdleConnections(60L, TimeUnit.SECONDS)\n            .setRetryHandler(DefaultHttpRequestRetryHandler.INSTANCE)\n            .setMaxConnTotal(100)\n            .setMaxConnPerRoute(50)\n            .build();\n    }\n\n    public <T> IMResult<T> httpJsonPost(String path, Object object, Class<T> clazz) throws Exception{\n        return httpJsonPost(imurl, channelId, httpClient, path, object, clazz, post -> {\n            int nonce = (int)(Math.random() * 100000 + 3);\n            long timestamp = System.currentTimeMillis();\n            String str = nonce + \"|\" + channelSecret + \"|\" + timestamp;\n            String sign = DigestUtils.sha1Hex(str);\n\n            post.setHeader(\"Content-type\", \"application/json; charset=utf-8\");\n            post.setHeader(\"Connection\", \"Keep-Alive\");\n            post.setHeader(\"nonce\", nonce + \"\");\n            post.setHeader(\"timestamp\", \"\" + timestamp);\n            post.setHeader(\"cid\", channelId);\n            post.setHeader(\"sign\", sign);\n        });\n    }\n\n    public String getChannelId() {\n        return channelId;\n    }\n\n    public String getChannelSecret() {\n        return channelSecret;\n    }\n\n    @Override\n    public void close() throws IOException {\n        httpClient.close();\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/utilities/ClassUtil.java",
    "content": "/*\n * This file is part of the Wildfire Chat package.\n * (c) Heavyrain2012 <heavyrain.lee@gmail.com>\n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\npackage cn.wildfirechat.sdk.utilities;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.URL;\nimport java.net.URLClassLoader;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\n/**\n * 类工具类\n * <p>\n * 提供类加载和扫描相关的工具方法，用于获取指定包下的所有类。\n * 支持从文件系统和JAR包中加载类。\n * </p>\n */\npublic class ClassUtil {\n\n    /**\n     * 获取同一路径下所有子类或接口实现类\n     *\n     * @param cls\n     * @return\n     * @throws IOException\n     * @throws ClassNotFoundException\n     */\n    public static List<Class<?>> getAllAssignedClass(Class<?> cls) throws IOException,\n        ClassNotFoundException {\n        List<Class<?>> classes = new ArrayList<Class<?>>();\n        for (Class<?> c : getClasses(cls)) {\n            if (cls.isAssignableFrom(c) && !cls.equals(c)) {\n                classes.add(c);\n            }\n        }\n        return classes;\n    }\n\n    /**\n     * 取得当前类路径下的所有类\n     *\n     * @param cls\n     * @return\n     * @throws IOException\n     * @throws ClassNotFoundException\n     */\n    public static List<Class<?>> getClasses(Class<?> cls) throws IOException,\n        ClassNotFoundException {\n        String pk = cls.getPackage().getName();\n//        String path = pk.replace('.', '/');\n//        ClassLoader classloader = Thread.currentThread().getContextClassLoader();\n//        URL url = classloader.getResource(path);\n//        String type = url.getProtocol();\n//\n//        System.out.println(\"the type is \" + type);\n//        System.out.println(url.getPath());\n//\n//        return getClasses(new File(url.getFile()), pk);\n        List<String> classNames = getClassName(pk, true);\n        List<Class<?>> classes = new ArrayList<>();\n        for (String className :\n             classNames) {\n            if (className.endsWith(\".class\")) {\n                className = className.substring(0, className.length() - 6);\n                className = className.substring(className.lastIndexOf(\"/\")+1, className.length());\n            }\n\n            classes.add(Class.forName(className));\n        }\n        return classes;\n    }\n\n    /**\n     * 迭代查找类\n     *\n     * @param dir\n     * @param pk\n     * @return\n     * @throws ClassNotFoundException\n     */\n    private static List<Class<?>> getClasses(File dir, String pk) throws ClassNotFoundException {\n        System.out.println(dir.getAbsolutePath());\n        List<Class<?>> classes = new ArrayList<Class<?>>();\n        if (!dir.exists()) {\n            return classes;\n        }\n        for (File f : dir.listFiles()) {\n            if (f.isDirectory()) {\n                classes.addAll(getClasses(f, pk + \".\" + f.getName()));\n            }\n            String name = f.getName();\n            if (name.endsWith(\".class\")) {\n                classes.add(Class.forName(pk + \".\" + name.substring(0, name.length() - 6)));\n            }\n        }\n        return classes;\n    }\n\n\n\n\n    /**\n     * 获取某包下所有类\n     * @param packageName 包名\n     * @param childPackage 是否遍历子包\n     * @return 类的完整名称\n     */\n    public static List<String> getClassName(String packageName, boolean childPackage) {\n        List<String> fileNames = null;\n        ClassLoader loader = Thread.currentThread().getContextClassLoader();\n        String packagePath = packageName.replace(\".\", \"/\");\n        URL url = loader.getResource(packagePath);\n        if (url != null) {\n            String type = url.getProtocol();\n            if (type.equals(\"file\")) {\n                fileNames = getClassNameByFile(url.getPath(), null, childPackage);\n            } else if (type.equals(\"jar\")) {\n                fileNames = getClassNameByJar(url.getPath(), childPackage);\n            }\n        } else {\n            fileNames = getClassNameByJars(((URLClassLoader) loader).getURLs(), packagePath, childPackage);\n        }\n        return fileNames;\n    }\n\n    /**\n     * 从项目文件获取某包下所有类\n     * @param filePath 文件路径\n     * @param className 类名集合\n     * @param childPackage 是否遍历子包\n     * @return 类的完整名称\n     */\n    private static List<String> getClassNameByFile(String filePath, List<String> className, boolean childPackage) {\n        List<String> myClassName = new ArrayList<String>();\n        File file = new File(filePath);\n        File[] childFiles = file.listFiles();\n        for (File childFile : childFiles) {\n            if (childFile.isDirectory()) {\n                if (childPackage) {\n                    myClassName.addAll(getClassNameByFile(childFile.getPath(), myClassName, childPackage));\n                }\n            } else {\n                String childFilePath = childFile.getPath();\n                if (childFilePath.endsWith(\".class\")) {\n                    if (childFilePath.indexOf(\"\\\\classes\") >= 0 || childFilePath.indexOf(\"/classes\") >= 0) {\n                        int start = childFilePath.indexOf(\"\\\\classes\");\n                        if (start == -1) {\n                            start = childFilePath.indexOf(\"/classes\");\n                        }\n                        childFilePath = childFilePath.substring(start + 9, childFilePath.lastIndexOf(\".\"));\n                    }\n                    childFilePath = childFilePath.replace(\"\\\\\", \".\");\n                    childFilePath = childFilePath.replace(\"/\", \".\");\n                    myClassName.add(childFilePath);\n                }\n            }\n        }\n\n        return myClassName;\n    }\n\n    /**\n     * 从jar获取某包下所有类\n     * @param jarPath jar文件路径\n     * @param childPackage 是否遍历子包\n     * @return 类的完整名称\n     */\n    private static List<String> getClassNameByJar(String jarPath, boolean childPackage) {\n        List<String> myClassName = new ArrayList<String>();\n        String[] jarInfo = jarPath.split(\"!\");\n        String jarFilePath = jarInfo[0].substring(jarInfo[0].indexOf(\"/\"));\n        String packagePath = jarInfo[1].substring(1);\n        try {\n            JarFile jarFile = new JarFile(jarFilePath);\n            Enumeration<JarEntry> entrys = jarFile.entries();\n            while (entrys.hasMoreElements()) {\n                JarEntry jarEntry = entrys.nextElement();\n                String entryName = jarEntry.getName();\n\n                if (entryName.endsWith(\".class\")) {\n                    if (childPackage) {\n                        if (entryName.startsWith(packagePath)) {\n                            entryName = entryName.replace(\"/\", \".\").substring(0, entryName.lastIndexOf(\".\"));\n                            myClassName.add(entryName);\n                        }\n                    } else {\n                        int index = entryName.lastIndexOf(\"/\");\n                        String myPackagePath;\n                        if (index != -1) {\n                            myPackagePath = entryName.substring(0, index);\n                        } else {\n                            myPackagePath = entryName;\n                        }\n                        if (myPackagePath.equals(packagePath)) {\n                            entryName = entryName.replace(\"/\", \".\").substring(0, entryName.lastIndexOf(\".\"));\n                            myClassName.add(entryName);\n                        }\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return myClassName;\n    }\n\n    /**\n     * 从所有jar中搜索该包，并获取该包下所有类\n     * @param urls URL集合\n     * @param packagePath 包路径\n     * @param childPackage 是否遍历子包\n     * @return 类的完整名称\n     */\n    private static List<String> getClassNameByJars(URL[] urls, String packagePath, boolean childPackage) {\n        List<String> myClassName = new ArrayList<String>();\n        if (urls != null) {\n            for (int i = 0; i < urls.length; i++) {\n                URL url = urls[i];\n                String urlPath = url.getPath();\n                // 不必搜索classes文件夹\n                if (urlPath.endsWith(\"classes/\")) {\n                    continue;\n                }\n                String jarPath = urlPath + \"!/\" + packagePath;\n                myClassName.addAll(getClassNameByJar(jarPath, childPackage));\n            }\n        }\n        return myClassName;\n    }\n\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/utilities/HttpUtils.java",
    "content": "package cn.wildfirechat.sdk.utilities;\n\nimport cn.wildfirechat.common.ErrorCode;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.HttpStatus;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.DefaultHttpRequestRetryHandler;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.impl.conn.PoolingHttpClientConnectionManager;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.nio.charset.StandardCharsets;\nimport java.security.SecureRandom;\nimport java.util.concurrent.TimeUnit;\n\n/**\n * HTTP工具类\n * <p>\n * 提供HTTP请求相关的工具方法，包括：\n * <ul>\n * <li>HTTP POST请求</li>\n * <li>HTTP GET请求</li>\n * <li>响应处理</li>\n * <li>日志记录</li>\n * </ul>\n * </p>\n */\npublic class HttpUtils extends JsonUtils {\n    // ======================== 常量定义（消除硬编码）========================\n    private static final Logger LOG = LoggerFactory.getLogger(HttpUtils.class);\n    public static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();\n\n    public static interface HeaderCallback {\n        public void addHeaders(HttpPost httpPost);\n    }\n\n    // ======================== HTTP JSON POST请求 ========================\n    public static <T> IMResult<T> httpJsonPost(String adminUrl, String adminSecret, HttpClient httpClient, String path, Object object, Class<T> clazz, HeaderCallback headerCallback) throws Exception {\n        // 前置校验\n        validateInitStatus(adminUrl, adminSecret, httpClient);\n        if (isNullOrEmpty(path)) {\n            throw new IllegalArgumentException(\"请求路径不能为空\");\n        }\n\n        String url = adminUrl + path;\n        HttpPost httpPost = new HttpPost(url);\n        try {\n            headerCallback.addHeaders(httpPost);\n\n            // 设置请求体\n            String jsonStr = object == null ? \"\" : GSON.toJson(object);\n            LOG.info(\"HTTP POST请求：{}，请求体：{}\", url, truncateLogContent(jsonStr));\n            StringEntity entity = new StringEntity(jsonStr, StandardCharsets.UTF_8);\n            entity.setContentEncoding(StandardCharsets.UTF_8.name());\n            entity.setContentType(\"application/json\");\n            httpPost.setEntity(entity);\n\n            // 执行请求并处理响应\n            HttpResponse response = httpClient.execute(httpPost);\n            return handleResponse(response, clazz, adminUrl, adminSecret);\n        } catch (Exception e) {\n            LOG.error(\"HTTP POST请求失败，路径：{}\", path, e);\n            throw new Exception(\"HTTP POST请求异常：\" + e.getMessage(), e);\n        } finally {\n            httpPost.releaseConnection();\n        }\n    }\n\n    // ======================== 私有工具方法 ========================\n    /**\n     * 校验初始化状态\n     */\n    protected static void validateInitStatus(String adminUrl, String adminSecret, HttpClient httpClient) {\n        if (isNullOrEmpty(adminUrl) || isNullOrEmpty(adminSecret) || httpClient == null) {\n            String errorMsg = \"野火IM Server SDK未初始化，请调用AdminConfig.initAdmin(AdminUrl, AdminSecret)完成初始化\";\n            LOG.error(errorMsg);\n            throw new IllegalStateException(errorMsg);\n        }\n    }\n\n    /**\n     * 处理HTTP响应，统一解析逻辑\n     */\n    protected static <T> IMResult<T> handleResponse(HttpResponse response, Class<T> clazz, String adminUrl, String adminSecret) throws Exception {\n        int statusCode = response.getStatusLine().getStatusCode();\n        String content = readResponseContent(response);\n\n        // 非200状态码处理\n        if (statusCode != HttpStatus.SC_OK) {\n            String errorMsg = String.format(\"HTTP请求失败，状态码：%d，响应内容：%s\", statusCode, truncateLogContent(content));\n            LOG.error(errorMsg);\n            throw new Exception(errorMsg);\n        }\n\n        // 解析响应体\n        IMResult<T> result = fromJsonObject(content, clazz);\n        if (result != null) {\n            if (result.getErrorCode() == ErrorCode.ERROR_CODE_AUTH_FAILURE) {\n                LOG.error(\"鉴权失败，请检查IM服务地址({})或密钥({})配置\", adminUrl, maskSecret(adminSecret));\n            } else if (result.getErrorCode() == ErrorCode.ERROR_CODE_SIGN_EXPIRED) {\n                LOG.error(\"签名过期，请确保当前服务与IM服务({})时间同步\", adminUrl);\n            }\n        }\n        return result;\n    }\n\n    /**\n     * 读取响应体（兼容分块传输，修复getContentLength=-1问题）\n     */\n    protected static String readResponseContent(HttpResponse response) throws IOException {\n        if (response.getEntity() == null) {\n            return \"\";\n        }\n\n        // 使用try-with-resources自动关闭所有流，避免资源泄漏\n        try (InputStream is = response.getEntity().getContent();\n             InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);\n             BufferedReader br = new BufferedReader(isr)) {\n\n            StringBuilder sb = new StringBuilder();\n            String line;\n            String nl = System.getProperty(\"line.separator\");\n            while ((line = br.readLine()) != null) {\n                sb.append(line).append(nl);\n            }\n            String content = sb.toString().trim();\n            LOG.info(\"HTTP响应内容：{}\", truncateLogContent(content));\n            return content;\n        }\n    }\n\n    /**\n     * 截断超长日志内容（避免日志爆炸）\n     */\n    protected static String truncateLogContent(String content) {\n        if (content == null) {\n            return \"\";\n        }\n        int maxLength = 1024;\n        return content.length() > maxLength ? content.substring(0, maxLength) + \"...\" : content;\n    }\n\n    /**\n     * 掩码处理密钥（避免日志泄露敏感信息）\n     */\n    protected static String maskSecret(String secret) {\n        if (isNullOrEmpty(secret) || secret.length() <= 4) {\n            return \"******\";\n        }\n        return secret.substring(0, 2) + \"******\" + secret.substring(secret.length() - 2);\n    }\n\n    /**\n     * 空值判断（补充实现，避免依赖外部未定义方法）\n     */\n    public static boolean isNullOrEmpty(String str) {\n        return str == null || str.trim().isEmpty();\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/utilities/JsonUtils.java",
    "content": "package cn.wildfirechat.sdk.utilities;\n\nimport cn.wildfirechat.pojos.mesh.MeshRestResult;\nimport cn.wildfirechat.sdk.model.IMResult;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport ikidou.reflect.TypeBuilder;\n\n/**\n * JSON工具类\n * <p>\n * 提供JSON序列化和反序列化的工具方法。\n * </p>\n */\npublic class JsonUtils {\n    public static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();\n    public static <T> IMResult<T> fromJsonObject(String content, Class<T> clazz) {\n        TypeBuilder builder = TypeBuilder.newInstance(IMResult.class);\n        if (!clazz.equals(Void.class)) {\n            builder.addTypeParam(clazz);\n        }\n        return gson.fromJson(content, builder.build());\n    }\n\n    public static <T> MeshRestResult<T> fromJsonObject2(String content, Class<T> clazz) {\n        TypeBuilder builder = TypeBuilder.newInstance(MeshRestResult.class);\n        if (!clazz.equals(Void.class)) {\n            builder.addTypeParam(clazz);\n        }\n        return gson.fromJson(content, builder.build());\n    }\n\n    public static <T, K> T fromJsonObject3(String content, Class<T> cls, Class<K> clazz) {\n        TypeBuilder builder = TypeBuilder.newInstance(cls);\n        if (!clazz.equals(Void.class)) {\n            builder.addTypeParam(clazz);\n        }\n        return gson.fromJson(content, builder.build());\n    }\n\n    public static boolean isNullOrEmpty(String str) {\n        return str == null || str.isEmpty();\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/cn/wildfirechat/sdk/utilities/RobotHttpUtils.java",
    "content": "package cn.wildfirechat.sdk.utilities;\n\nimport cn.wildfirechat.sdk.model.IMResult;\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport ikidou.reflect.TypeBuilder;\nimport io.netty.util.internal.StringUtil;\nimport org.apache.commons.codec.digest.DigestUtils;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.HttpStatus;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.config.RequestConfig;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.StringEntity;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.DefaultHttpRequestRetryHandler;\nimport org.apache.http.impl.client.HttpClientBuilder;\nimport org.apache.http.impl.client.HttpClients;\nimport org.apache.http.impl.conn.PoolingHttpClientConnectionManager;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.BufferedReader;\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.lang.reflect.Type;\nimport java.net.MalformedURLException;\nimport java.net.URL;\nimport java.nio.charset.Charset;\nimport java.util.concurrent.TimeUnit;\n\n\n/**\n * 机器人HTTP工具类\n * <p>\n * 提供机器人API调用的HTTP工具方法，包括初始化、请求签名、HTTP请求等。\n * 继承自HttpUtils并实现Closeable接口，专门用于机器人接口的调用。\n * </p>\n */\npublic class RobotHttpUtils extends HttpUtils implements Closeable {\n    private static final Logger LOG = LoggerFactory.getLogger(RobotHttpUtils.class);\n    public static final Gson gson = new GsonBuilder().disableHtmlEscaping().create();\n\n    private final String url;\n    private final String robotId;\n    private final String robotSecret;\n    private final CloseableHttpClient httpClient;\n\n    private final int port;\n\n    private void checkPort() {\n        if (port != 80 && port != 443 && port != -1) {\n            if (port == 18080) {\n                LOG.warn(\"您传入的机器人API地址中的端口是18080，18080端口默认为管理API端口，机器人API端口应该为IM服务的HTTP端口，默认为80，请确认是否使用错误！\");\n            } else {\n                LOG.warn(\"您传入的机器人API地址中的端口不是80/443，机器人API的端口和客户端使用端口一样，都应该为IM服务的HTTP端口，默认为80，请确实是否正确？如果您定制化了IM服务端口或者使用其他端口反向代理IM服务的HTTP端口请忽略此提示。\");\n            }\n        }\n    }\n\n    public RobotHttpUtils(String url, String robotId, String robotSecret) {\n        this.url = url.trim();\n        this.robotId = robotId.trim();\n        this.robotSecret = robotSecret.trim();\n        try {\n            URL u = new URL(this.url);\n            int port = u.getPort();\n            if(port == -1) {\n                port = u.getDefaultPort();\n            }\n            this.port = port;\n        } catch (MalformedURLException e) {\n            throw new RuntimeException(e);\n        }\n        checkPort();\n        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();\n        cm.setValidateAfterInactivity(1000);\n        int connectTimeout = 5000; // 连接超时时间\n        int socketTimeout = 15000; // 请求超时时间\n        int connectionRequestTimeout = 3000; // 从连接池获取连接的超时时间\n        RequestConfig requestConfig = RequestConfig.custom()\n            .setConnectTimeout(connectTimeout)\n            .setSocketTimeout(socketTimeout)\n            .setConnectionRequestTimeout(connectionRequestTimeout)\n            .build();\n        httpClient = HttpClients.custom()\n            .setDefaultRequestConfig(requestConfig)\n            .setConnectionManager(cm)\n            .evictExpiredConnections()\n            .evictIdleConnections(60L, TimeUnit.SECONDS)\n            .setRetryHandler(DefaultHttpRequestRetryHandler.INSTANCE)\n            .setMaxConnTotal(100)\n            .setMaxConnPerRoute(50)\n            .build();\n    }\n\n\n    public <T> IMResult<T> httpJsonPost(String path, Object object, Class<T> clazz) throws Exception{\n        return httpJsonPost(url, robotId, httpClient, path, object, clazz, post -> {\n            int nonce = (int)(Math.random() * 100000 + 3);\n            long timestamp = System.currentTimeMillis();\n            String str = nonce + \"|\" + robotSecret + \"|\" + timestamp;\n            String sign = DigestUtils.sha1Hex(str);\n\n            post.setHeader(\"Content-type\", \"application/json; charset=utf-8\");\n            post.setHeader(\"Connection\", \"Keep-Alive\");\n            post.setHeader(\"nonce\", nonce + \"\");\n            post.setHeader(\"timestamp\", \"\" + timestamp);\n            post.setHeader(\"rid\", robotId);\n            post.setHeader(\"sign\", sign);\n        });\n    }\n\n    public String getRobotId() {\n        return robotId;\n    }\n\n    public String getRobotSecret() {\n        return robotSecret;\n    }\n\n    public CloseableHttpClient getHttpClient() {\n        return httpClient;\n    }\n\n    @Override\n    public void close() throws IOException {\n        httpClient.close();\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/ikidou/reflect/TypeBuilder.java",
    "content": "/*\n * Copyright 2016 ikidou\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 ikidou.reflect;\n\nimport ikidou.reflect.exception.TypeException;\nimport ikidou.reflect.typeimpl.ParameterizedTypeImpl;\nimport ikidou.reflect.typeimpl.WildcardTypeImpl;\n\nimport java.lang.reflect.Type;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class TypeBuilder {\n    private final TypeBuilder parent;\n    private final Class raw;\n    private final List<Type> args = new ArrayList<>();\n\n\n    private TypeBuilder(Class raw, TypeBuilder parent) {\n        assert raw != null;\n        this.raw = raw;\n        this.parent = parent;\n    }\n\n    public static TypeBuilder newInstance(Class raw) {\n        return new TypeBuilder(raw, null);\n    }\n\n    private static TypeBuilder newInstance(Class raw, TypeBuilder parent) {\n        return new TypeBuilder(raw, parent);\n    }\n\n\n    public TypeBuilder beginSubType(Class raw) {\n        return newInstance(raw, this);\n    }\n\n    public TypeBuilder endSubType() {\n        if (parent == null) {\n            throw new TypeException(\"expect beginSubType() before endSubType()\");\n        }\n\n        parent.addTypeParam(getType());\n\n        return parent;\n    }\n\n    public TypeBuilder addTypeParam(Class clazz) {\n        return addTypeParam((Type) clazz);\n    }\n\n    public TypeBuilder addTypeParamExtends(Class... classes) {\n        if (classes == null) {\n            throw new NullPointerException(\"addTypeParamExtends() expect not null Class\");\n        }\n\n        WildcardTypeImpl wildcardType = new WildcardTypeImpl(null, classes);\n\n        return addTypeParam(wildcardType);\n    }\n\n    public TypeBuilder addTypeParamSuper(Class... classes) {\n        if (classes == null) {\n            throw new NullPointerException(\"addTypeParamSuper() expect not null Class\");\n        }\n\n        WildcardTypeImpl wildcardType = new WildcardTypeImpl(classes, null);\n\n        return addTypeParam(wildcardType);\n    }\n\n    public TypeBuilder addTypeParam(Type type) {\n        if (type == null) {\n            throw new NullPointerException(\"addTypeParam expect not null Type\");\n        }\n\n        args.add(type);\n\n        return this;\n    }\n\n    public Type build() {\n        if (parent != null) {\n            throw new TypeException(\"expect endSubType() before build()\");\n        }\n\n        return getType();\n    }\n\n    private Type getType() {\n        if (args.isEmpty()) {\n            return raw;\n        }\n        return new ParameterizedTypeImpl(raw, args.toArray(new Type[args.size()]), null);\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/ikidou/reflect/TypeToken.java",
    "content": "/*\n * Copyright 2016 ikidou\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 ikidou.reflect;\n\nimport ikidou.reflect.exception.TypeException;\n\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\n\npublic abstract class TypeToken<T> {\n    private final Type type;\n\n    public TypeToken() {\n        Type superclass = getClass().getGenericSuperclass();\n        if (superclass instanceof Class) {\n            throw new TypeException(\"No generics found!\");\n        }\n        ParameterizedType type = (ParameterizedType) superclass;\n        this.type = type.getActualTypeArguments()[0];\n    }\n\n    public Type getType() {\n        return type;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/ikidou/reflect/exception/TypeException.java",
    "content": "/*\n * Copyright 2016 ikidou\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 ikidou.reflect.exception;\n\npublic class TypeException extends RuntimeException {\n    public TypeException() {\n    }\n\n    public TypeException(String message) {\n        super(message);\n    }\n\n    public TypeException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public TypeException(Throwable cause) {\n        super(cause);\n    }\n\n    public TypeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {\n        super(message, cause, enableSuppression, writableStackTrace);\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/ikidou/reflect/typeimpl/ParameterizedTypeImpl.java",
    "content": "/*\n * Copyright 2016 ikidou\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 ikidou.reflect.typeimpl;\n\nimport ikidou.reflect.exception.TypeException;\n\nimport java.lang.reflect.ParameterizedType;\nimport java.lang.reflect.Type;\nimport java.lang.reflect.TypeVariable;\nimport java.util.Arrays;\n\n@SuppressWarnings(\"SpellCheckingInspection\")\npublic class ParameterizedTypeImpl implements ParameterizedType {\n    private final Class raw;\n    private final Type[] args;\n    private final Type owner;\n\n    public ParameterizedTypeImpl(Class raw, Type[] args, Type owner) {\n        this.raw = raw;\n        this.args = args != null ? args : new Type[0];\n        this.owner = owner;\n        checkArgs();\n    }\n\n    private void checkArgs() {\n        if (raw == null) {\n            throw new TypeException(\"raw class can't be null\");\n        }\n        TypeVariable[] typeParameters = raw.getTypeParameters();\n        if (args.length != 0 && typeParameters.length != args.length) {\n            throw new TypeException(raw.getName() + \" expect \" + typeParameters.length + \" arg(s), got \" + args.length);\n        }\n    }\n\n    @Override\n    public Type[] getActualTypeArguments() {\n        return args;\n    }\n\n    @Override\n    public Type getRawType() {\n        return raw;\n    }\n\n    @Override\n    public Type getOwnerType() {\n        return owner;\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder sb = new StringBuilder();\n        sb.append(raw.getName());\n        if (args.length != 0) {\n            sb.append('<');\n            for (int i = 0; i < args.length; i++) {\n                if (i != 0) {\n                    sb.append(\", \");\n                }\n                Type type = args[i];\n                if (type instanceof Class) {\n                    Class clazz = (Class) type;\n\n                    if (clazz.isArray()) {\n                        int count = 0;\n                        do {\n                            count++;\n                            clazz = clazz.getComponentType();\n                        } while (clazz.isArray());\n\n                        sb.append(clazz.getName());\n\n                        for (int j = count; j > 0; j--) {\n                            sb.append(\"[]\");\n                        }\n                    } else {\n                        sb.append(clazz.getName());\n                    }\n                } else {\n                    sb.append(args[i].toString());\n                }\n            }\n            sb.append('>');\n        }\n        return sb.toString();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        ParameterizedTypeImpl that = (ParameterizedTypeImpl) o;\n\n        if (!raw.equals(that.raw)) return false;\n        // Probably incorrect - comparing Object[] arrays with Arrays.equals\n        if (!Arrays.equals(args, that.args)) return false;\n        return owner != null ? owner.equals(that.owner) : that.owner == null;\n\n    }\n\n    @Override\n    public int hashCode() {\n        int result = raw.hashCode();\n        result = 31 * result + Arrays.hashCode(args);\n        result = 31 * result + (owner != null ? owner.hashCode() : 0);\n        return result;\n    }\n}\n"
  },
  {
    "path": "sdk/src/main/java/ikidou/reflect/typeimpl/WildcardTypeImpl.java",
    "content": "/*\n * Copyright 2016 ikidou\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 ikidou.reflect.typeimpl;\n\nimport java.lang.reflect.Type;\nimport java.lang.reflect.WildcardType;\nimport java.util.Arrays;\n\npublic class WildcardTypeImpl implements WildcardType {\n    private final Class[] upper;\n    private final Class[] lower;\n\n    public WildcardTypeImpl(Class[] lower, Class[] upper) {\n        this.lower = lower != null ? lower : new Class[0];\n        this.upper = upper != null ? upper : new Class[0];\n\n        checkArgs();\n    }\n\n    private void checkArgs() {\n        if (lower.length == 0 && upper.length == 0) {\n            throw new IllegalArgumentException(\"lower or upper can't be null\");\n        }\n\n        checkArgs(lower);\n        checkArgs(upper);\n    }\n\n    private void checkArgs(Class[] args) {\n        for (int i = 1; i < args.length; i++) {\n            Class clazz = args[i];\n            if (!clazz.isInterface()) {\n                throw new IllegalArgumentException(clazz.getName() + \" not a interface!\");\n            }\n        }\n    }\n\n    @Override\n    public Type[] getUpperBounds() {\n        return upper;\n    }\n\n    @Override\n    public Type[] getLowerBounds() {\n        return lower;\n    }\n\n    @Override\n    public String toString() {\n        if (upper.length > 0) {\n            if (upper[0] == Object.class) {\n                return \"?\";\n            }\n            return getTypeString(\"? extends \", upper);\n        } else {\n            return getTypeString(\"? super \", lower);\n        }\n    }\n\n    private String getTypeString(String prefix, Class[] type) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(prefix);\n\n        for (int i = 0; i < type.length; i++) {\n            if (i != 0) {\n                sb.append(\" & \");\n            }\n            sb.append(type[i].getName());\n        }\n\n        return sb.toString();\n\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        WildcardTypeImpl that = (WildcardTypeImpl) o;\n\n        return Arrays.equals(upper, that.upper) && Arrays.equals(lower, that.lower);\n\n    }\n\n    @Override\n    public int hashCode() {\n        int result = Arrays.hashCode(upper);\n        result = 31 * result + Arrays.hashCode(lower);\n        return result;\n    }\n}\n"
  },
  {
    "path": "systemd/README.md",
    "content": "# Linux Service 方式运行\n除了命令行方式直接执行IM服务外，还可以以linux systemd service方式来运行，注意以这种方式运行，im服务的配置还是需要按照常规方法来配置。\n\n## 获取软件包\n如果是社区版可以下载野火release或则会自己源码编译，得到软件压缩包```distribution-bundle-tar.tar.gz```、```im-server.deb```和```im-server.rpm```。如果是专业版使用专业版邮件里的链接下载软件压缩包，下载后先解压一次，得到```distribution-bundle-tar.tar.gz```、```im-server.deb```和```im-server.rpm```。\n> ```im-server.deb```和```im-server.rpm```文件可能带有版本号，下面使用过程中，请注意修正为实际的文件名称。\n\n## 手动部署\n### 依赖\n野火IM依赖JRE1.8手动部署需要手动安装JRE1.8，确保命令:```java -version```能看到正确的java版本信息才行。\n\n### 部署软件包\n创建```/opt/im-server```目录，把软件包```distribution-bundle-tar.tar.gz```解压到这个目录下。解压后这个目录下有```bin```、```config```、```lib```、```systemd```等目录。\n\n### 放置systemd server file\n把```systemd```目录下的```im-server.service```文件放到```/usr/lib/systemd/system/```目录下。然后执行命令```sudo systemctl daemon-reload```。\n\n### 目录结构\n所有目录都在```/opt/im-server```目录下。包括日志目录、配置目录等。\n\n### 测试\n根据下面管理服务的说明，启动服务，查看控制台日志，确认启动没有异常，服务器本地执行 ```curl -v http://127.0.0.1/api/version``` 能够返回版本的JSON信息。\n\n## 安装部署\n### 依赖\n安装包安装将会自动安装依赖，不需要手动安装java。如果服务器上有其他版本的Java，请注意可能的冲突问题。\n\n### 部署软件包\n可以直接安装```deb```和```rpm```格式的安装包，在debian系的linux系统（Ubuntu等使用```apt```命令安装软件的系统）中，使用命令：\n```shell\nsudo apt install ./im-server.deb\n```\n\n在红帽系的linux系统（Centos等使用```yum```命令安装软件的系统）中，使用命令:\n```shell\nsudo yum install ./im-server.rpm\n```\n\n注意在上述两个命令中，都使用的是本地安装，注意安装包名前的```./```路径。如果使用```dpkg -i ./im-server.deb```命令将不会安装依赖。 \n\n### 目录结构\n* /etc/im-server/config     配置文件目录\n* /opt/im-server            程序目录\n* /var/log/im-server        日志目录\n* /var/lib/im-server/h2db   H2数据库目录，如果使用mysql则不会使用\n* /var/lib/im-server/media  内置对象存储数据目录，如果使用非内置，则目录不会使用。\n\n\n### 测试\n根据下面管理服务的说明，启动服务，查看控制台日志，确认启动没有异常，服务器本地执行 ```curl -v http://127.0.0.1/api/version``` 能够返回版本的JSON信息。\n\n## 管理服务\n* 刷新配置，当安装或者更新后需要执行： ```sudo systemctl daemon-reload```\n* 启动服务： ```sudo systemctl start im-server```\n* 停止服务： ```sudo systemctl stop im-server```\n* 重启服务： ```sudo systemctl restart im-server```\n* 查看服务状态：```sudo systemctl status im-server```\n* 设置开机自启动：```sudo systemctl enable im-server```\n* 禁止开机自启动：```sudo systemctl disable im-server```\n* 查看控制台日志: ```journalctl -f -u im-server```\n\n## 修改服务内存大小\n修改```/opt/im-server/bin/wildfirechat.sh```文件的倒数3、4行。打开Xmx和Xms配置，设置为合适的内存大小。\n\n## 配置\n需要对IM服务配置来达到最好的执行效果，手动部署配置文件在````/opt/im-server/config````目录下，安装部署的配置文件在````/etc/im-server/config````目录下。\n\n## 日志\n手动部署的日志文件在```/opt/im-server/logs```目录下，安装部署的日志在```/var/log/im-server```目录下。如果需要提供日志给野火官方，请把这个目录下的日志和制台日志(```journalctl -f -u im-server```)一起发给野火。\n\n手动部署也可以修改目录，可以修改配置文件目录下的```config/log4j2.xml```修改日志的路径。\n\n"
  },
  {
    "path": "systemd/im-server.service",
    "content": "[Unit]\nDescription=IM Server\nDocumentation=https://docs.wildfirechat.cn\nWants=network-online.target\nAfter=network-online.target\n\n[Service]\nWorkingDirectory=/opt/im-server\nExecStart=/bin/sh bin/wildfirechat.sh 2>&1\n\n# Let systemd restart this service always\nRestart=always\nRestartSec=5\n\n# Specifies the maximum file descriptor number that can be opened by this process\nLimitNOFILE=65536\n\n# Specifies the maximum number of threads this process can create\nTasksMax=infinity\n\n# Disable timeout logic and wait until process is stopped\nTimeoutStopSec=infinity\nSendSIGKILL=no\n\n[Install]\nWantedBy=multi-user.target\n"
  }
]